/**
* Upload the next fragment
*
* @param array $config FTP/SFTP connection details
*
* @throws Exception
*
* @return array
*/
public function uploadChunk(array $config)
{
$ret = ['result' => true, 'done' => false, 'message' => '', 'totalSize' => 0, 'doneSize' => 0];
// Get information from the session
$session = $this->container->session;
$fragSize = $session->get('transfer.fragSize', 5242880, 'akeeba');
$backup = $session->get('transfer.lastBackup', [], 'akeeba');
$totalSize = $session->get('transfer.totalSize', 0, 'akeeba');
$doneSize = $session->get('transfer.doneSize', 0, 'akeeba');
$part = $session->get('transfer.part', -1, 'akeeba');
$frag = $session->get('transfer.frag', -1, 'akeeba');
// Do I need to update the total size?
if (!$totalSize) {
$totalSize = $backup['total_size'];
$session->set('transfer.totalSize', $totalSize, 'akeeba');
}
$ret['totalSize'] = $totalSize;
// First fragment of a new part
if ($frag == -1) {
$frag = 0;
$part++;
}
// If I'm past the last part I'm done
if ($part >= $backup['multipart']) {
// We are done
$ret['done'] = true;
return $ret;
}
// Get the information for this part
$fileName = $this->getPartFilename($backup['absolute_path'], $part);
$fileSize = filesize($fileName);
$intendedSeekPosition = $fragSize * $frag;
// I am trying to seek past EOF. Oops. Upload the next part.
if ($intendedSeekPosition >= $fileSize) {
$session->set('transfer.frag', -1, 'akeeba');
return $this->uploadChunk($config);
}
// Open the part
$fp = @fopen($fileName, 'rb');
if ($fp === false) {
$ret['result'] = false;
$ret['message'] = JText::sprintf('COM_AKEEBA_TRANSFER_ERR_CANNOTREADLOCALFILE', $fileName);
return $ret;
}
// Seek to position
if (fseek($fp, $intendedSeekPosition) == -1) {
@fclose($fp);
$ret['result'] = false;
$ret['message'] = JText::sprintf('COM_AKEEBA_TRANSFER_ERR_CANNOTREADLOCALFILE', $fileName);
return $ret;
}
// Read the data
$data = fread($fp, $fragSize);
$doneSize += strlen($data);
$ret['doneSize'] = $doneSize;
$session->set('transfer.doneSize', $doneSize, 'akeeba');
// Upload the data
$session = $this->container->session;
$url = $session->get('transfer.url', '', 'akeeba');
$directory = $session->get('transfer.targetPath', '', 'akeeba');
$url = rtrim($url, '/') . '/kickstart.php';
$uri = JUri::getInstance($url);
$uri->setVar('task', 'uploadFile');
$uri->setVar('file', basename($fileName));
$uri->setVar('directory', $directory);
$uri->setVar('frag', $frag);
$uri->setVar('fragSize', $fragSize);
$downloader = new Download($this->container);
$downloader->setAdapterOptions([CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => ['data' => $data]]);
$dataLength = strlen($data);
unset($data);
$rawData = $downloader->getFromURL($uri->toString());
// Close the part
fclose($fp);
// Try to get the raw JSON data
$pos = strpos($rawData, '###');
if ($pos === false) {
// Invalid AJAX data, no leading ###
throw new RuntimeException(JText::sprintf('COM_AKEEBA_TRANSFER_ERR_CANNOTUPLOADARCHIVE', basename($fileName)));
}
// Remove the leading ###
$rawData = substr($rawData, $pos + 3);
$pos = strpos($rawData, '###');
if ($pos === false) {
// Invalid AJAX data, no trailing ###
throw new RuntimeException(JText::sprintf('COM_AKEEBA_TRANSFER_ERR_CANNOTUPLOADARCHIVE', basename($fileName)));
}
// Remove the trailing ###
$rawData = substr($rawData, 0, $pos);
// Get the JSON response
$data = @json_decode($rawData, true);
if (empty($data)) {
// Invalid AJAX data, can't decode this stuff
throw new RuntimeException(JText::sprintf('COM_AKEEBA_TRANSFER_ERR_CANNOTUPLOADARCHIVE', basename($fileName)));
}
if (!$data['status']) {
throw new RuntimeException(JText::sprintf('COM_AKEEBA_TRANSFER_ERR_ERRORFROMREMOTE', $data['message']));
}
// Update the session data
$session->set('transfer.fragSize', $fragSize, 'akeeba');
$session->set('transfer.totalSize', $totalSize, 'akeeba');
$session->set('transfer.doneSize', $doneSize, 'akeeba');
$session->set('transfer.part', $part, 'akeeba');
$session->set('transfer.frag', ++$frag, 'akeeba');
// Did I go past EOF? Then on to the next part
$intendedSeekPosition += $dataLength;
if ($intendedSeekPosition >= $fileSize) {
$session->set('transfer.frag', -1, 'akeeba');
$session->set('transfer.part', ++$part, 'akeeba');
}
// Did I reach the last part? Then I'm done
if ($part >= $backup['multipart']) {
// We are done
$ret['done'] = true;
}
return $ret;
}