3v4l.org

run code in 300+ PHP versions simultaneously
<?php declare (strict_types = 1); // change to if(0) to allow fpm/apache/etc modes.. if (1) { if (php_sapi_name() !== 'cli') { die("for security reasons, only cli mode is allowed."); } } init(); $save_path = ''; // will be set by get_url() $url = get_url(); $ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_ENCODING => '', CURLOPT_USERAGENT => '4chan_backuper_php; libcurl/' . (curl_version()['version']) . ' php/' . PHP_VERSION, CURLOPT_RETURNTRANSFER => 1, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_AUTOREFERER => 1, )); $html = fetch($url); m200(); $new_domd = my_dom_loader($html); $new_xp = new DOMXPath($new_domd); if (!file_exists($save_path . "index.html")) { //var_dump(base64_encode($new_domd->saveHTML())); $clone = my_dom_loader($new_domd->saveHTML()); $clone_xp = new DOMXPath($clone); $should_be_removed = (int)($clone_xp->query("//div[@class='thread']")->item(0)->childNodes->length); $removed = 0; foreach ($clone_xp->query("//div[@class='thread']")->item(0)->childNodes as $child) { ++$removed; $child->parentNode->removeChild($child); } if ($removed !== $should_be_removed) { throw new \LogicException("removed: {$removed} - should be removed: {$should_be_removed}"); } file_put_contents($save_path . "index.html", $clone->saveHTML(), LOCK_EX); unset($clone, $clone_xp, $child); } $old_domd = my_dom_loader(file_get_contents($save_path . "index.html")); $old_xp = new DOMXPath($old_domd); $old_thread = $old_xp->query("//div[@class='thread']")->item(0); while (true) { $new_posts = 0; $new_images = 0; foreach ($new_xp->query("//div[@class='thread']//div[contains(@class,'postContainer') and @id]") as $post) { $id = $post->getAttribute("id"); assert(!empty($id)); if ($old_xp->query('//div[@id=' . xpath_quote($id) . ']')->length > 0) { //already processed this post. continue; } $old_thread->appendChild(($post = $old_domd->importNode($post, true))); ++$new_posts; $img = $post->getElementsByTagName("img"); if ($img->length < 1) { continue; } $img = $img->item(0); $a = $old_xp->query("//a[contains(@class,'fileThumb')]", $post); if ($a->length < 1) { continue; } $a = $a->item(0); $full_url = $a->getAttribute("href"); $full_bname = basename($full_url); if (empty($full_url) || empty($full_bname)) { continue; } $thumb_url = $img->getAttribute("src"); $thumb_bname = basename($full_url); if (empty($thumb_url) || empty($thumb_bname)) { continue; } ++$new_images; $thumb_binary = fetch($thumb_url); m200(); $full_binary = fetch($full_url); m200(); file_put_contents($save_path . "images" . DIRECTORY_SEPARATOR . "thumbnails" . DIRECTORY_SEPARATOR . $thumb_bname, $thumb_binary); file_put_contents($save_path . "images" . DIRECTORY_SEPARATOR . $full_bname, $full_binary); $a->setAttribute("href", "images/" . $full_bname); $img->setAttribute("src", "images/thumbnails/" . $thumb_bname); } if ($new_posts > 0 || $new_images > 0) { //file_put_contents($save_path . "index.html", $old_domd->saveHTML(), LOCK_EX); } echo "new posts: {$new_posts} - new images: {$new_images}\n"; $sleeptime = 10; echo "sleeping {$sleeptime} seconds and refetching.."; sleep($sleeptime); echo ".\nfetching again.\n"; $html = fetch($url); m200(); $new_domd = my_dom_loader($html); $new_xp = new DOMXPath($new_domd); } function my_dom_loader(string $html): \DOMDocument { $html = trim($html); if (empty($html)) { //.... } if (false === stripos($html, '<?xml encoding=')) { $html = '<?xml encoding="UTF-8">' . $html; } $ret = @DOMDocument::loadHTML($html, LIBXML_NOBLANKS | LIBXML_NONET | LIBXML_BIGLINES); if (!$ret) { throw new \Exception("failed to create DOMDocument from input html!"); } return $ret; } // "must be http 200" function m200(): void { global $ch; $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($code !== 200) { $url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); throw new \RuntimException("expected http \"200 OK\" but got {$code} - url: \"{$url}\""); } } function fetch(string $url, int &$code = null): string { if (substr($url, 0, 2) === "//") { $url = "http:" . $url; } echo "fetching \"{$url}\".."; global $ch; curl_setopt_array($ch, array( CURLOPT_URL => $url, )); $data = curl_exec($ch); if (curl_errno($ch) !== CURLE_OK) { throw new \RuntimeException("curl error: " . curl_errno($ch) . ": " . curl_error($ch)); } $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); echo "http code \"{$code}\"."; return $data; } function get_url(): string { global $argv; global $save_path; if (isset($_REQUEST['url'])) { echo "got url from \$_REQUEST\n"; $url = (string)$_REQUEST['url']; } elseif (!empty($argv) && count($argv) > 1) { echo "got url from \$argv\n"; $url = $argv; unset($url[0]); $url = implode("", $url); } elseif (php_sapi_name() === 'cli') { //interactive mode stream_set_blocking(STDIN, true); echo "enter 4chan url: "; $url = fgets(STDIN); } else { throw new \RuntimeException("url not specified! (and not running interactively)"); } $url = trim($url); if (!preg_match('/^(?:https?\:\/\/)?boards\.4chan\.org\/(?<board_name>.*?)\/.*?\/(?<thread_id>\d+)/', $url, $matches)) { throw new \RuntimeException("url \"{$url}\" does not look like a 4chan board url! - they are supposed to look something like http://boards.4chan.org/hc/thread/1501699#p1508333"); } $board_name = $matches['board_name']; $thread_id = $matches['thread_id']; $url = "http://boards.4chan.org/{$board_name}/thread/{$thread_id}"; echo "url parsed: \"{$url}\"\n"; $save_path = getcwd() . DIRECTORY_SEPARATOR . "backups"; mymkdir($save_path); $save_path .= DIRECTORY_SEPARATOR . $board_name; mymkdir($save_path); $save_path .= DIRECTORY_SEPARATOR . $thread_id; mymkdir($save_path); $save_path .= DIRECTORY_SEPARATOR; mymkdir($save_path . "images"); mymkdir($save_path . "images" . DIRECTORY_SEPARATOR . "thumbnails"); return $url; } function mymkdir(string $path): void { if (is_dir($path)) { return; } echo "making folder \"{$path}\".."; if (!mkdir($path)) { throw new \RuntimeException("ERROR: could not make folder!"); } echo ". done.\n"; } function init() { static $firstrun = true; if ($firstrun !== true) { return; } $firstrun = false; error_reporting(E_ALL); set_error_handler("hhb_exception_error_handler"); // ini_set("log_errors",'On'); // ini_set("display_errors",'On'); // ini_set("log_errors_max_len",'0'); // ini_set("error_prepend_string",'<error>'); // ini_set("error_append_string",'</error>'.PHP_EOL); // ini_set("error_log",__DIR__.DIRECTORY_SEPARATOR.'error_log.php.txt'); assert_options(ASSERT_ACTIVE, 1); assert_options(ASSERT_WARNING, 0); assert_options(ASSERT_QUIET_EVAL, 1); assert_options(ASSERT_CALLBACK, 'hhb_assert_handler'); } function hhb_exception_error_handler($errno, $errstr, $errfile, $errline) { if (!(error_reporting() & $errno)) { // This error code is not included in error_reporting return; } throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } function hhb_assert_handler($file, $line, $code, $desc = null) { $errstr = 'Assertion failed at ' . $file . ':' . $line . ' ' . $desc . ' code: ' . $code; throw new ErrorException($errstr, 0, 1, $file, $line); } //based on https://stackoverflow.com/a/1352556/1067003 function xpath_quote(string $value): string { if (false === strpos($value, '"')) { return '"' . $value . '"'; } if (false === strpos($value, '\'')) { return '\'' . $value . '\''; } // if the value contains both single and double quotes, construct an // expression that concatenates all non-double-quote substrings with // the quotes, e.g.: // // concat("'foo'", '"', "bar") $sb = 'concat('; $substrings = explode('"', $value); for ($i = 0; $i < count($substrings); ++$i) { $needComma = ($i > 0); if ($substrings[$i] !== '') { if ($i > 0) { $sb .= ', '; } $sb .= '"' . $substrings[$i] . '"'; $needComma = true; } if ($i < (count($substrings) - 1)) { if ($needComma) { $sb .= ', '; } $sb .= "'\"'"; } } $sb .= ')'; return $sb; }

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
8.3.60.0040.01118.55
8.3.50.0090.00919.16
8.3.40.0060.01019.06
8.3.30.0000.01818.79
8.3.20.0060.00321.10
8.3.10.0060.00321.90
8.3.00.0080.00022.04
8.2.180.0090.01316.73
8.2.170.0150.00622.96
8.2.160.0090.00620.47
8.2.150.0030.00524.18
8.2.140.0040.00424.66
8.2.130.0090.00017.97
8.2.120.0080.00026.35
8.2.110.0030.01322.14
8.2.100.0100.00618.03
8.2.90.0040.00418.00
8.2.80.0040.00417.97
8.2.70.0030.00618.16
8.2.60.0040.00418.16
8.2.50.0040.00718.10
8.2.40.0050.00319.59
8.2.30.0040.00420.80
8.2.20.0030.00518.34
8.2.10.0040.00419.66
8.2.00.0040.00418.29
8.1.280.0150.00425.92
8.1.270.0080.00022.18
8.1.260.0040.00426.35
8.1.250.0080.00028.09
8.1.240.0090.00022.48
8.1.230.0110.00017.95
8.1.220.0040.00417.91
8.1.210.0030.00618.77
8.1.200.0080.00317.60
8.1.190.0120.00017.22
8.1.180.0040.00418.10
8.1.170.0030.00518.83
8.1.160.0030.00619.05
8.1.150.0080.00019.10
8.1.140.0050.00219.09
8.1.130.0100.00020.30
8.1.120.0000.00917.52
8.1.110.0090.00317.59
8.1.100.0040.00417.54
8.1.90.0050.00317.60
8.1.80.0070.00317.62
8.1.70.0040.00417.55
8.1.60.0050.00317.74
8.1.50.0000.00817.59
8.1.40.0050.00317.57
8.1.30.0000.00817.70
8.1.20.0030.00617.73
8.1.10.0060.00317.60
8.1.00.0040.00417.67
8.0.300.0000.00821.70
8.0.290.0030.00517.00
8.0.280.0000.00818.46
8.0.270.0040.00417.48
8.0.260.0050.00518.47
8.0.250.0070.00017.18
8.0.240.0110.00017.14
8.0.230.0050.00217.08
8.0.220.0000.00717.12
8.0.210.0000.00717.02
8.0.200.0000.00817.23
8.0.190.0000.00917.09
8.0.180.0000.00717.07
8.0.170.0090.00017.06
8.0.160.0090.00017.11
8.0.150.0000.00817.05
8.0.140.0050.00317.11
8.0.130.0000.00613.52
8.0.120.0000.00817.09
8.0.110.0000.00817.08
8.0.100.0050.00317.04
8.0.90.0040.00416.95
8.0.80.0080.01117.04
8.0.70.0030.00616.97
8.0.60.0000.00816.95
8.0.50.0000.00717.14
8.0.30.0100.00717.37
8.0.20.0160.00617.27
8.0.10.0000.00817.24
8.0.00.0090.01017.07
7.4.330.0060.00016.71
7.4.320.0000.00716.78
7.4.300.0060.00016.53
7.4.290.0000.00916.57
7.4.280.0030.00616.52
7.4.270.0000.00716.80
7.4.260.0000.00716.80
7.4.250.0040.00416.64
7.4.240.0070.00016.81
7.4.230.0040.00416.75
7.4.220.0080.00016.85
7.4.210.0100.00816.76
7.4.200.0080.00016.84
7.4.160.0110.00816.71
7.4.140.0120.01217.86
7.4.130.0040.01316.82
7.4.120.0060.01716.72
7.4.110.0060.01216.71
7.4.100.0110.00916.88
7.4.90.0110.01416.66
7.4.80.0110.01119.39
7.4.70.0090.00916.80
7.4.60.0070.01016.69
7.4.50.0080.00816.63
7.4.40.0030.01616.89
7.4.00.0070.00714.98
7.3.330.0050.00013.45
7.3.320.0000.00613.55
7.3.310.0000.00816.62
7.3.300.0020.00516.59
7.3.290.0040.01116.63
7.3.280.0100.00816.58
7.3.260.0110.00916.73
7.3.240.0100.00816.73
7.3.230.0120.00616.62
7.3.210.0120.00916.83
7.3.200.0060.01116.53
7.3.190.0100.01016.59
7.3.180.0100.00716.64
7.3.170.0100.00616.68
7.3.160.0130.00716.66
7.3.40.0070.00714.96
7.3.30.0070.00415.02
7.3.20.0870.01015.23
7.3.10.0100.00415.18
7.3.00.0120.01815.02
7.2.330.0130.00716.79
7.2.320.0120.01116.96
7.2.310.0140.00416.98
7.2.300.0180.00016.90
7.2.290.0070.01116.82
7.2.170.0060.00615.34
7.2.160.0000.01114.98
7.2.150.0100.00315.24
7.2.140.0070.00715.13
7.2.130.0130.00315.26
7.2.120.0060.00615.18
7.2.110.0100.00315.48
7.2.100.0100.00715.11
7.2.90.0100.00315.39
7.2.80.0100.01615.12
7.2.70.0110.00615.05
7.2.60.0160.01015.31
7.2.50.0210.00615.13
7.2.40.0190.00615.35
7.2.30.0080.00915.50
7.2.20.0130.00615.25
7.2.10.0090.00915.41
7.2.00.0120.00615.29
7.1.280.0100.00314.16
7.1.270.0090.00414.11
7.1.260.0080.00814.09
7.1.250.0090.00614.05

preferences:
69.71 ms | 401 KiB | 5 Q