/** * 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; }