$val){ echo "$key: $val\n"; } echo 'CWD = '.getcwd()."\n"; } // first check for GET/POST if ($_SERVER['REQUEST_METHOD'] === 'GET') { // used for testing the compression response ?> Welcome to upload.php
" ?> 10) { $msg = "Error: TimeStamp is out of date\n" . "Data TS = $requestTime\n" . "Server TS = $receivedTime\n"; exitCode(422, $msg); } // The signature to test if (isset($_SERVER['HTTP_SIGNATURE'])) { $signatureSent = $_SERVER['HTTP_SIGNATURE']; } else { exitCode(422, 'Error: No signature'); } if (isset($_SERVER['HTTP_FILE'])) { $name = $_SERVER['HTTP_FILE']; // first check if the file is escaping our local folder structure if ($limitPath) { $name_dir = pathinfo($name)['dirname']; $name_fullpath = resolvePath($name_dir); $cwd = getcwd(); if (substr($name_fullpath, 0, strlen($cwd)) !== $cwd) { exitCode(500, 'Error: Attempting to escape local folder structure'); } } // if the file exists, check the file is writable if (file_exists($name)) { if (!is_writable($name)) { exitCode(500, "Error: Target file $name is not writable by this user " . `whoami`); } } else { if (!touch($name)) { exitCode(500, "Error: Cannot create the target file $name with this user " . `whoami`); } } } else { exitCode(422, 'Error: No filename'); } // Now what are we doing with the file? if (isset($_SERVER["HTTP_ACTION"])) { $action = $_SERVER['HTTP_ACTION']; } else { exitCode(422, 'Error: No action'); } if ($action !== 'replace' && $action !== 'append') { exitCode(422, "Error: Invalid header ACTION = $action"); } // If appending - get the earlist timestamp - JS timestamps overflow PHP int! if ($action === 'append') { if (isset($_SERVER['HTTP_OLDEST'])) { $oldestTs = (float)$_SERVER['HTTP_OLDEST']; } else { exitCode(422, 'Error: No oldest timestamp'); } } $utf8 = $_SERVER['HTTP_UTF8']; if ($utf8 != '0' && $utf8 != '1') { // default to UTF-8 as before if not supplied $utf8 = '1'; } $binary = $_SERVER['HTTP_BINARY']; if ($binary != '0' && $binary != '1') { exitCode(422, "Error: Invalid header BINARY = $binary"); } if (isset($_SERVER['HTTP_RAW_POST_DATA'])) { $data = $_SERVER['HTTP_RAW_POST_DATA']; } else { $data = file_get_contents('php://input'); } if (strlen($data) == 0) { exitCode(422, 'Error: No data sent'); } if (isset($_SERVER['HTTP_CONTENT_ENCODING'])) { if ($_SERVER['HTTP_CONTENT_ENCODING'] == 'gzip') { echo "Unzipping data\n"; $data = gzdecode($data); } elseif ($_SERVER['HTTP_CONTENT_ENCODING'] == 'deflate') { echo "Inflating data\n"; $data = gzinflate($data); } } if ($debug) { //echo "Data = $data\n"; } // --------------------------------------------------------------- // Check the signature sent matches what we calculate // --------------------------------------------------------------- $ourSignature = CalculateSignature($secret, $requestTime . $name . $data); if ($signatureSent != $ourSignature) { $msg = "Error: Invalid signature\n" . "Data Sig = $signatureSent\n" . "Server Sig = $ourSignature\n" . "Server sig data = " . $requestTime . $name . substr($data, 0, 50); exitCode(422, $msg); } // change encoding if required if ($utf8 == '0') { $data = mb_convert_encoding($data, "ISO-8859-1", "UTF-8"); } // --------------------------------------------------------------- // Finally, do the processing // --------------------------------------------------------------- if ($action === 'replace') { // do we need to decode a base64 string back to binary data echo 'Opening ' . ($binary == '1' ? 'binary' : 'text') . " file $name for replacement\n"; if ($binary == '1') { $data = base64_decode($data); } WriteFile($name, $data, $binary == '1'); exitCode(200); } else if ($action === 'append') { // first check we have some data to append! $dataObj = json_decode($data, false); if (is_null($dataObj)) { exitCode(500, 'No valid JSON data in the received data'); } // next check we have an existing file to append // if not then just write the new data to a dest file echo "Opening text file $name for appending\n"; if (!file_exists($name) || filesize($name) === 0) { echo "No existing file to append data - $name\n"; WriteFile($name, $data); exitCode(200); } // open the target file for reading if (!$outFile = fopen($name, 'r')) { exitCode(500, "Failed to open file $name"); } $fileObj = json_decode(fgets($outFile), false); fclose($outFile); // no valid data in the dest file if (is_null($fileObj)) { echo "No valid JSON data in - $name\n"; echo "Writing data as a new file\n"; WriteFile($name, $data); exitCode(200); } if ($debug) { echo "New data:\n"; var_dump($dataObj); echo "\n"; } // remove the old data foreach ($fileObj as $key => $val) { if (is_null($val)) { continue; } // $val format is [[ts,val],[ts,val]...] if ($debug) { echo "Processing entry $key\n"; } $arr = $val; do { if (sizeof($arr) > 0 && $arr[0][0] < $oldestTs) { if ($debug) { echo "Removing entry $key - ".$arr[0][0]."\n"; } array_shift($arr); } else { break; } } while(true); $fileObj->$key = $arr; } // append the new data foreach ($dataObj as $key => $val) { if (is_null($val)) { continue; } if ($debug) { echo "Appending new data: $key - ".sizeof($val)."\n"; } if (sizeof($val) > 0) { $fileObj->$key = array_merge($fileObj->$key, $val); } } // write the file back again echo "Appending text file $name\n"; WriteFile($name, json_encode($fileObj)); } else { exitCode(422, 'Error: Invalid action'. $action); } exitCode(200); ///////// end of script ////////// // --------------------------------------------------------------- // Helpers // --------------------------------------------------------------- function CalculateSignature($secret, $data) { return hash_hmac('sha256', $data, $secret, false); } function WriteFile($filename, $content, $binary=false) { // open the target file for writing $mode = 'w' . ($binary ? 'b': ''); $outFile = fopen($filename, $mode) or die("Cannot create file $filename with mode $mode"); if (!$outFile) { echo "Failed to open file $filename - mode $mode"; http_response_code(500); exit; } echo 'Writing ' . ($binary ? 'binary': 'text') . " file $filename\n"; if (fwrite($outFile, $content) == FALSE) { echo "Write failed"; http_response_code(500); } else { echo 'Write complete'; } fclose($outFile); } set_exception_handler(function($ex) { echo "\nException occurred!\n\n"; echo print_r($ex); exitCode(500); }); function resolvePath($path) { if(DIRECTORY_SEPARATOR !== '/') { $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); } $search = explode('/', $path); $search = array_filter($search, function($part) { return $part !== '.'; }); $append = array(); $match = false; while(count($search) > 0) { $match = realpath(implode('/', $search)); if($match !== false) { break; } array_unshift($append, array_pop($search)); }; if($match === false) { $match = getcwd(); } if(count($append) > 0) { $match .= DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $append); } return $match; } function exitCode($code, $msg=null) { if (null !== $msg) echo $msg; http_response_code($code); //header('Connection: close'); header('Content-Length: '.ob_get_length()); ob_end_flush(); // Strange behaviour, will not work flush(); // Unless both are called ! exit; }