/** Function endElement */ public function endElement($parser, $name) { $parent = $this->getParent(); // should be before endElement parent::endElement($parser, $name); if ($this->UploadError) { return; } if ($name == 'FILE' && $parent == 'UPLOAD') { $this->UploadFile->BuildId = $this->BuildId; // Close base64 temporary file writing handler fclose($this->Base64TmpFileWriteHandle); unset($this->Base64TmpFileWriteHandle); // Decode file using 'read by chunk' approach to minimize memory footprint // Note: Using stream_filter_append/stream_copy_to_stream is more efficient but // return an "invalid byte sequence" on windows $rhandle = fopen($this->Base64TmpFilename, 'r'); $whandle = fopen($this->TmpFilename, 'w+'); $chunksize = 4096; while (!feof($rhandle)) { fwrite($whandle, base64_decode(fread($rhandle, $chunksize))); } fclose($rhandle); unset($rhandle); fclose($whandle); unset($whandle); // Delete base64 encoded file $success = cdash_unlink($this->Base64TmpFilename); if (!$success) { add_log("Failed to delete file '" . $this->Base64TmpFilename . "'", __FILE__ . ':' . __LINE__ . ' - ' . __FUNCTION__, LOG_WARNING); } // Check file size against the upload quota $upload_file_size = filesize($this->TmpFilename); $Project = new Project(); $Project->Id = $this->projectid; $Project->Fill(); if ($upload_file_size > $Project->UploadQuota) { add_log("Size of uploaded file {$this->TmpFilename} is {$upload_file_size} bytes, which is greater " . "than the total upload quota for this project ({$Project->UploadQuota} bytes)", __FILE__ . ':' . __LINE__ . ' - ' . __FUNCTION__, LOG_ERR); $this->UploadError = true; cdash_unlink($this->TmpFilename); return; } // Compute SHA1 of decoded file $upload_file_sha1 = sha1_file($this->TmpFilename); // TODO Check if a file if same buildid, sha1 and name has already been uploaded $this->UploadFile->Sha1Sum = $upload_file_sha1; $this->UploadFile->Filesize = $upload_file_size; // Extension of the file indicates if it's a data file that should be hosted on CDash of if // an URL should just be considered. File having extension ".url" are expected to contain an URL. $path_parts = pathinfo($this->UploadFile->Filename); $ext = $path_parts['extension']; if ($ext == "url") { $this->UploadFile->IsUrl = true; // Read content of the file $url_length = 255; // max length of 'uploadfile.filename' field $this->UploadFile->Filename = trim(file_get_contents($this->TmpFilename, NULL, NULL, 0, $url_length)); cdash_unlink($this->TmpFilename); //add_log("this->UploadFile->Filename '".$this->UploadFile->Filename."'", __FILE__.':'.__LINE__.' - '.__FUNCTION__, LOG_INFO); } else { $this->UploadFile->IsUrl = false; $upload_dir = realpath($GLOBALS['CDASH_UPLOAD_DIRECTORY']); if (!$upload_dir) { add_log("realpath cannot resolve CDASH_UPLOAD_DIRECTORY '" . $GLOBALS['CDASH_UPLOAD_DIRECTORY'] . "' with cwd '" . getcwd() . "'", __FILE__ . ':' . __LINE__ . ' - ' . __FUNCTION__, LOG_WARNING); } $upload_dir .= '/' . $this->UploadFile->Sha1Sum; $uploadfilepath = $upload_dir . '/' . $this->UploadFile->Sha1Sum; // Check if upload directory should be created if (!file_exists($upload_dir)) { $success = mkdir($upload_dir); if (!$success) { add_log("Failed to create directory '" . $upload_dir . "'", __FILE__ . ':' . __LINE__ . ' - ' . __FUNCTION__, LOG_ERR); $this->UploadError = true; return; } } // Check if file has already been referenced if (!file_exists($uploadfilepath)) { $success = rename($this->TmpFilename, $uploadfilepath); if (!$success) { add_log("Failed to rename file '" . $this->TmpFilename . "' into '" . $uploadfilepath . "'", __FILE__ . ':' . __LINE__ . ' - ' . __FUNCTION__, LOG_ERR); $this->UploadError = true; return; } } else { // Delete decoded temporary file since it has already been addressed $success = cdash_unlink($this->TmpFilename); if (!$success) { add_log("Failed to delete file '" . $this->TmpFilename . "'", __FILE__ . ':' . __LINE__ . ' - ' . __FUNCTION__, LOG_WARNING); } } // Generate symlink name $symlinkName = $path_parts['basename']; // Check if symlink should be created $createSymlink = !file_exists($upload_dir . '/' . $symlinkName); if ($createSymlink) { // Create symlink if (function_exists("symlink")) { $success = symlink($uploadfilepath, $upload_dir . '/' . $symlinkName); } else { $success = 0; } if (!$success) { // Log actual non-testing symlink failure as an error: $level = LOG_ERR; // But if testing, log as info only: if ($GLOBALS['CDASH_TESTING_MODE']) { $level = LOG_INFO; } add_log("Failed to create symlink [target:'" . $uploadfilepath . "', name: '" . $upload_dir . '/' . $symlinkName . "']", __FILE__ . ':' . __LINE__ . ' - ' . __FUNCTION__, $level); // Fall back to a full copy if symlink does not exist, or if it failed: $success = copy($uploadfilepath, $upload_dir . '/' . $symlinkName); if (!$success) { add_log("Failed to copy file (symlink fallback) [target:'" . $uploadfilepath . "', name: '" . $upload_dir . '/' . $symlinkName . "']", __FILE__ . ':' . __LINE__ . ' - ' . __FUNCTION__, LOG_ERR); $this->UploadError = true; return; } } } } // Update model $success = $this->UploadFile->Insert(); if (!$success) { add_log("UploadFile model - Failed to insert row associated with file: '" . $this->UploadFile->Filename . "'", __FILE__ . ':' . __LINE__ . ' - ' . __FUNCTION__, LOG_ERR); } $Project->CullUploadedFiles(); // Reset UploadError so that the handler could attempt to process following files $this->UploadError = false; } }