=== ARBORESCENCE (Sans images/logs) === . ./contexte_projet.txt ./dl.php ./jobs.sqlite3 ./php-error.log ./uploads ./uploads/php0FTT92.jpg ./uploads/php0INu1S.jpg ./uploads/php17PU4f.jpg ./uploads/php17YUQS.jpg ./uploads/php20kJrY.jpg ./uploads/php21lanC.jpg ./uploads/php2KVQS8.jpg ./uploads/php2Ko0aN.jpg ./uploads/php2mNjIs.jpg ./uploads/php2tMayy.jpg ./uploads/php3KU2ri.jpg ./uploads/php3fJt1x.jpg ./uploads/php4F0rJ0.jpg ./uploads/php4GdkbY.jpg ./uploads/php4QfjKk.jpg ./uploads/php4b79tH.jpg ./uploads/php54bECD.jpg ./uploads/php55CdOT.jpg ./uploads/php5DHtvd.jpg ./uploads/php5Ndlbv.jpg ./uploads/php5ZCp8E.jpg ./uploads/php60VjJB.jpg ./uploads/php6FQCxC.jpg ./uploads/php75FEpq.jpg ./uploads/php7FZPgW.jpg ./uploads/php7N2MWo.jpg ./uploads/php86sZsI.jpg ./uploads/php8Iiu7X.jpg ./uploads/php8KsbXN.jpg ./uploads/php8LyBqs.jpg ./uploads/php8Nanhp.jpg ./uploads/php8YfDQc.jpg ./uploads/php8wfxTX.jpg ./uploads/php8z6A4e.jpg ./uploads/php92GKXc.jpg ./uploads/php9bNacR.jpg ./uploads/php9ebfEL.jpg ./uploads/php9wnQhW.jpg ./uploads/phpAAaQoi.jpg ./uploads/phpAgMRq1.jpg ./uploads/phpBBC2Rp.jpg ./uploads/phpBJJOcy.jpg ./uploads/phpBeGDKL.jpg ./uploads/phpC4uqad.jpg ./uploads/phpCJeCOU.jpg ./uploads/phpCPh9KY.jpg ./uploads/phpCf3jlo.jpg ./uploads/phpCkzF0v.jpg ./uploads/phpCupUf0.jpg ./uploads/phpD5jc7P.jpg ./uploads/phpDG4QGE.jpg ./uploads/phpDU2VdF.jpg ./uploads/phpDhGdQ2.jpg ./uploads/phpDibc8L.jpg ./uploads/phpDqAObn.jpg ./uploads/phpDw63aB.jpg ./uploads/phpERQBep.jpg ./uploads/phpEUDuvU.jpg ./uploads/phpEV1foI.jpg ./uploads/phpEecy9g.jpg ./uploads/phpFs8Szn.jpg ./uploads/phpGLPzTD.jpg ./uploads/phpGMOKqj.jpg ./uploads/phpGTyvVG.jpg ./uploads/phpGZ6UBu.jpg ./uploads/phpGffCps.jpg ./uploads/phpGtpjEv.jpg ./uploads/phpH2f00L.jpg ./uploads/phpHBpWqV.jpg ./uploads/phpHMYK2E.jpg ./uploads/phpHlEUSc.jpg ./uploads/phpICc6Od.jpg ./uploads/phpIO8zvv.jpg ./uploads/phpImGhKo.jpg ./uploads/phpJX5ABL.jpg ./uploads/phpJb8qVP.jpg ./uploads/phpJh8ops.jpg ./uploads/phpJugfnO.jpg ./uploads/phpK3q6wK.jpg ./uploads/phpKSzX8j.jpg ./uploads/phpKakcZY.jpg ./uploads/phpKtXFwb.jpg ./uploads/phpL0t3kq.jpg ./uploads/phpL59OGc.jpg ./uploads/phpL6SLJB.jpg ./uploads/phpLV10qH.jpg ./uploads/phpLiQtby.jpg ./uploads/phpLlVXcf.jpg ./uploads/phpLqd5Pt.jpg ./uploads/phpM1eWbd.jpg ./uploads/phpMYYP41.jpg ./uploads/phpMcP0CD.jpg ./uploads/phpMp8R40.jpg ./uploads/phpNDMts5.jpg ./uploads/phpNYNwj6.jpg ./uploads/phpNYS6Bh.jpg ./uploads/phpNxriX8.jpg ./uploads/phpO1RVc1.jpg ./uploads/phpOCSEld.jpg ./uploads/phpOek1lm.jpg ./uploads/phpOwpVtS.jpg ./uploads/phpP2Rqol.jpg ./uploads/phpP3U8Hl.jpg ./uploads/phpPzQ8XF.jpg ./uploads/phpQ3BVAB.jpg ./uploads/phpQD0nrX.jpg ./uploads/phpQjnGvT.jpg ./uploads/phpRABbno.jpg ./uploads/phpRpEwmf.jpg ./uploads/phpRrjES6.jpg ./uploads/phpS2so7i.jpg ./uploads/phpS38Tj0.jpg ./uploads/phpSzv5MH.jpg ./uploads/phpTRPNdk.jpg ./uploads/phpTUxc9x.jpg ./uploads/phpTf4FZC.jpg ./uploads/phpTftu90.jpg ./uploads/phpUACvv4.jpg ./uploads/phpUETRxk.jpg ./uploads/phpUGkHBF.jpg ./uploads/phpUYkmpe.jpg ./uploads/phpUbEcH2.jpg ./uploads/phpUiNWBE.jpg ./uploads/phpUjh8ow.jpg ./uploads/phpV5xWzn.jpg ./uploads/phpVAAYpd.jpg ./uploads/phpVHBMin.jpg ./uploads/phpVHQl1s.jpg ./uploads/phpVsPdwd.jpg ./uploads/phpVtyvsP.jpg ./uploads/phpVuLwFB.jpg ./uploads/phpVx6WP2.jpg ./uploads/phpWP0PFI.jpg ./uploads/phpWVMt99.jpg ./uploads/phpXx4WRG.jpg ./uploads/phpY2fTM9.jpg ./uploads/phpY8fxBA.jpg ./uploads/phpYJXsCy.jpg ./uploads/phpYxPh19.jpg ./uploads/phpZEYf40.jpg ./uploads/phpZd96aJ.jpg ./uploads/phpaBmdfE.jpg ./uploads/phpaI6o1N.jpg ./uploads/phpackCYE.jpg ./uploads/phpamWAgB.jpg ./uploads/phpb5Wmfr.jpg ./uploads/phpbUjUsp.jpg ./uploads/phpbX49Kv.jpg ./uploads/phpbtcHs2.jpg ./uploads/phpcMiFTE.jpg ./uploads/phpceOSLD.jpg ./uploads/phpcks66x.jpg ./uploads/phpdUslqi.jpg ./uploads/phpdjltkk.jpg ./uploads/phpdxGmj7.jpg ./uploads/phpeTx55r.jpg ./uploads/phpeiuFRO.jpg ./uploads/phpf2aocs.jpg ./uploads/phpfIMd7T.jpg ./uploads/phpfSvuCX.jpg ./uploads/phpfev6XL.jpg ./uploads/phpfhqWXh.jpg ./uploads/phpfoARAT.jpg ./uploads/phpg4gHh0.jpg ./uploads/phpgHSbcC.jpg ./uploads/phph5Y67a.jpg ./uploads/phphI65Wc.jpg ./uploads/phphLiJQP.jpg ./uploads/phphTcTTB.jpg ./uploads/phpiFI6Yf.jpg ./uploads/phpiQQJdG.jpg ./uploads/phpiugDwI.jpg ./uploads/phpj13gHM.jpg ./uploads/phpjBUaIl.jpg ./uploads/phpjCO2fs.jpg ./uploads/phpjbPt6U.jpg ./uploads/phpkIKDfg.jpg ./uploads/phpkZIfoD.jpg ./uploads/phpkkSLA7.jpg ./uploads/phpkpdRbY.jpg ./uploads/phpl38E5o.jpg ./uploads/phpl8PhYk.jpg ./uploads/phplcnGrO.jpg ./uploads/phplmG1QZ.jpg ./uploads/phplmzwxu.jpg ./uploads/phpm5rMjz.jpg ./uploads/phpmPM3eR.jpg ./uploads/phpmZdGCY.jpg ./uploads/phpn79R0a.jpg ./uploads/phpn81rO9.jpg ./uploads/phpnJ9UIo.jpg ./uploads/phpnRddFn.jpg ./uploads/phpnSozDN.jpg ./uploads/phpnTDE8L.jpg ./uploads/phpngI9cg.jpg ./uploads/phpnmXnri.jpg ./uploads/phpoLPXB8.jpg ./uploads/phpoPHbLR.jpg ./uploads/phpoR6EOl.jpg ./uploads/phpoT69Ap.jpg ./uploads/phpoaXS7Q.jpg ./uploads/phpok54Ln.jpg ./uploads/phpp1Hwvk.jpg ./uploads/phpp2iZhF.jpg ./uploads/phpp9Nosl.jpg ./uploads/phppHdCBB.jpg ./uploads/phppPORYv.jpg ./uploads/phppQoASc.jpg ./uploads/phppsKX49.jpg ./uploads/phppwZO2V.jpg ./uploads/phpq3ZNIe.jpg ./uploads/phpqGfHm2.jpg ./uploads/phpqSSi7C.jpg ./uploads/phpqYB8Qa.jpg ./uploads/phpqlzjwl.jpg ./uploads/phpqtouRL.jpg ./uploads/phpr2oMvB.jpg ./uploads/phprAIDTd.jpg ./uploads/phprJgjTK.jpg ./uploads/phprO7lD0.jpg ./uploads/phprYb6xR.jpg ./uploads/phprj2ip2.jpg ./uploads/phprrfaAm.jpg ./uploads/phps0yKgl.jpg ./uploads/phps2PI08.jpg ./uploads/phpsQJz4z.jpg ./uploads/phpsh96gh.jpg ./uploads/phpsysvSy.jpg ./uploads/phpszYbu9.jpg ./uploads/phpt3Bzhz.jpg ./uploads/phptNGX8M.jpg ./uploads/phptTzlnw.jpg ./uploads/phpuDV9YO.jpg ./uploads/phpuWzNUO.jpg ./uploads/phpv2mICo.jpg ./uploads/phpvAziZY.jpg ./uploads/phpvKyXTp.jpg ./uploads/phpvL8yoC.jpg ./uploads/phpvW9ZiE.jpg ./uploads/phpvYcAIb.jpg ./uploads/phpvZxNW6.jpg ./uploads/phpvo1762.jpg ./uploads/phpvryMzc.jpg ./uploads/phpw5T5Ss.jpg ./uploads/phpwDXpdc.jpg ./uploads/phpwZxqJZ.jpg ./uploads/phpxCaW83.jpg ./uploads/phpxGZI1R.jpg ./uploads/phpxS0vab.jpg ./uploads/phpxjsC2d.jpg ./uploads/phpy7JmNn.jpg ./uploads/phpyD8SWg.jpg ./uploads/phpyFn34s.jpg ./uploads/phpyOqfKt.jpg ./uploads/phpyfuXfx.jpg ./uploads/phpyiCeTT.jpg ./uploads/phpykfp6U.jpg ./uploads/phpzActeB.jpg === CONTENU DES FICHIERS === --- FICHIER: ./dl.php --- 'There is no file uploaded', 'error_processing_file' => 'Error processing uploaded file!', 'error_api_key' => 'APIKEY not correct! Check APIKEY in dl.php and photobooth config.', 'error_empty_file' => 'The file is empty.', 'error_large_file' => 'The file is too large', 'error_not_allowed' => 'File not allowed.', 'error_cannot_find_file' => 'Cannot find uploaded file', 'error_upload_failed' => 'Photobooth had problems uploading the file, check photobooth log for errors', 'download_or_share' => 'Download or Share Your File', 'download_button' => 'Download', 'share_button' => 'Share', 'share_title' => 'Photobooth File', 'share_text' => 'Check out this file I took!', 'successful_share' => 'Successful share', 'error_sharing' => 'Error sharing', 'error_runtime' => 'Runtime error: ', 'endpoint_not_exist' => 'Endpoint does not exist!', 'info_version' => 'version', 'info_name' => 'photobooth-app file upload extension', ]; // internal constants - do not change below this! $VERSION = 2; $DB_FILENAME = "jobs.sqlite3"; $ALLOWED_UPLOAD_TYPES = [ 'image/png' => 'png', 'image/jpeg' => 'jpg', 'image/gif' => 'gif', 'video/mp4' => 'mp4', ]; // setup php ini ini_set('display_errors', 0); ini_set('display_startup_errors', 0); ini_set("log_errors", 1); ini_set("error_log", "php-error.log"); error_reporting(E_ALL); // prevent nginx from additional buffering because the long running job would fail then // nginx has additional buffer to php, the php buffer is flushed, but nginx not header('X-Accel-Buffering: no'); // https://stackoverflow.com/a/25017347 ob_implicit_flush(true); // flush always after any write to buffer without additional call to flush needed. function text_to_image($text, $image_width = 400, $colour = array(0, 244, 34), $background = array(0, 0, 0)) { # some endpoints usually output images # if there is an error in the process, a placeholder image is generated so # there is at least something shown to the user why it failed $font = 50; $line_height = 15; $padding = 5; $text = wordwrap($text, ($image_width / 10)); $lines = explode("\n", $text); $image = imagecreate($image_width, ((count($lines) * $line_height)) + ($padding * 2)); $background = imagecolorallocate($image, $background[0], $background[1], $background[2]); $colour = imagecolorallocate($image, $colour[0], $colour[1], $colour[2]); imagefill($image, 0, 0, $background); $i = $padding; foreach ($lines as $line) { imagestring($image, $font, $padding, $i, trim($line), $colour); $i += $line_height; } header("Content-type: image/jpeg"); header('Content-Disposition: inline; filename="err.jpg"'); http_response_code(500); imagejpeg($image); imagedestroy($image); } function api_key_set() { global $APIKEY; // die if APIKEY is not set if (strlen($APIKEY) < 8) { throw new RuntimeException('$APIKEY is empty or too short in dl.php script! Configure $APIKEY in dl.php and photoboothapp-config to pair systems.'); } if (stripos($APIKEY, "changedefault!") !== false) { throw new RuntimeException('$APIKEY is default in dl.php script! Change $APIKEY in dl.php and photoboothapp-config to pair systems.'); } } function isSecure() { if ( (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443 ) { return true; } // Check for HTTPS in the "X-Forwarded-Proto" header for reverse proxies if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { return true; } return false; } try { // db connection setup $db = new SQLite3($DB_FILENAME); $db->busyTimeout(200); // WAL mode has better control over concurrency. // Source: https://www.sqlite.org/wal.html #$db->exec('PRAGMA journal_mode = wal;'); // setup checks # create working directory if (!is_dir($WORK_DIRECTORY)) { mkdir($WORK_DIRECTORY); } # create DB $db->exec("CREATE TABLE IF NOT EXISTS upload_requests( file_identifier TEXT PRIMARY KEY, filename TEXT, last_modified TEXT DEFAULT CURRENT_TIMESTAMP, status TEXT NOT NULL DEFAULT 'pending' )"); if (($_POST["action"] ?? null) == "upload" && ($_POST["id"] ?? null)) { // action: upload a file, identified by id. // once file uploaded, mark it as "uploaded" in db // ongoing download-action would check for "uploaded" mark and return the file then api_key_set(); $file_identifier = $_POST["id"]; // sanity check for apikey if ($_POST["apikey"] !== $APIKEY) { $db->exec("UPDATE upload_requests SET status = 'upload_failed' WHERE file_identifier = '" . $file_identifier . "'"); throw new RuntimeException($translations['error_api_key']); } // file upload sanity checks if (!isset($_FILES["upload_file"])) { # set status to fail so ongoing download can stop waiting $db->exec("UPDATE upload_requests SET status = 'upload_failed' WHERE file_identifier = '" . $file_identifier . "'"); throw new RuntimeException($translations['error_no_file_uploaded'] . " ($file_identifier)"); } if ($_FILES['upload_file']['error'] != UPLOAD_ERR_OK) { throw new RuntimeException($translations['error_processing_file'] . " Errorcode=" . $_FILES['upload_file']['error']); } $filepath = $_FILES['upload_file']['tmp_name']; if (empty($filepath)) { throw new RuntimeException("tmp_name is empty, pls check php settings (upload size, ...)!"); } try { $mimetype = mime_content_type($filepath); } catch (ValueError $e) { throw new RuntimeException("Mimetype of file could not be detected. Aborting."); } if (filesize($filepath) === 0) { throw new RuntimeException($translations['error_empty_file']); } if (filesize($filepath) > $ALLOWED_UPLOAD_MAX_SIZE) { throw new RuntimeException($translations['error_large_file']); } if (!in_array($mimetype, array_keys($ALLOWED_UPLOAD_TYPES))) { throw new RuntimeException($translations['error_not_allowed']); } // filename to store the uploaded file to in work directory $filename = basename($filepath); $extension = $ALLOWED_UPLOAD_TYPES[$mimetype]; // query entry for id to double-check that currently uploaded file was actually requested and job assigned $results = $db->querySingle("SELECT * FROM upload_requests WHERE file_identifier='" . $file_identifier . "' AND status='job_assigned'", true); if (!empty($results)) { $db->exec("UPDATE upload_requests SET status = 'uploading' WHERE file_identifier = '" . $file_identifier . "'"); // save uploaded file $newFilepath = $WORK_DIRECTORY . "/" . $filename . "." . $extension; if (!copy($filepath, $newFilepath)) { // Copy the file, returns false if failed throw new RuntimeException("Can't move file."); } unlink($filepath); // Delete the temp file // mark as uploaded $db->exec("UPDATE upload_requests SET filename = '$filename.$extension', status = 'uploaded' WHERE file_identifier = '" . $file_identifier . "'"); echo "file successfully saved and ready to download"; } else throw new RuntimeException("error processing job"); } elseif (($_POST["action"] ?? null) == "upload_queue") { // longrunning task to wait for dl request api_key_set(); // sanity check for apikey if ($_POST["apikey"] !== $APIKEY) { throw new RuntimeException($translations['error_api_key']); } $LOOP_TIME = 0.5; # loop every x seconds $LOOP_TIME_MAX = 240; # after x seconds, the script terminates and the client is expected to create a new connection latest $time_processed = 0; do { $results = $db->querySingle("SELECT * FROM upload_requests WHERE status = 'pending'", true); if (!empty($results)) { // non-empty results is to upload by photobooth-app $db->exec("UPDATE upload_requests SET status = 'job_assigned' WHERE file_identifier = '" . $results['file_identifier'] . "'"); echo json_encode($results); } else { # nothing to do; send ping message to ensure connection health and have regular input to shareservice.py echo json_encode(['ping' => time()]); } # add newline so python backend can read it echo "\n"; # flush content to output if (ob_get_level() > 0) ob_flush(); # flush internal buffer (needed for php builtin webserver during testing) flush(); # flush output buffer # wait before next iteration usleep($LOOP_TIME * 1000 * 1000); $time_processed += $LOOP_TIME; } while ($time_processed <= $LOOP_TIME_MAX); } elseif (($_GET["action"] ?? null) == "download" && ($_GET["id"] ?? null)) { api_key_set(); $file_identifier = $_GET["id"]; $db->exec("REPLACE INTO upload_requests ( file_identifier, status ) VALUES ( '$file_identifier', 'pending')"); $time_waited = 0; do { $results = $db->querySingle("SELECT * FROM upload_requests WHERE file_identifier= '$file_identifier'", true); if (!empty($results) && $results["status"] == "uploaded") { $file = $WORK_DIRECTORY . "/" . $results["filename"]; if (file_exists($file)) { $mimetype = mime_content_type($file); $fileData = file_get_contents($file); $base64EncodedData = base64_encode($fileData); $isImage = in_array($mimetype, ['image/png', 'image/jpeg', 'image/gif']); $isVideo = ($mimetype == 'video/mp4'); echo "