Error : $errstr
in file '$errfile' (line '$errline').
ErrCode : $errno HTML; return true; }); class App { /** * plugins path in vendor * @var string */ public const PLUGINS_PATH = 'vendor/picocms/plugins/'; /** * themes path in vendor * @var string */ public const THEMES_PATH = 'vendor/picocms/themes/'; /** * Pico instance. * @var Pico */ protected $pico; public function __construct(string $contentFolderFromRoot, ?TestInterface $testRunner = null) { // sanitize content folder $cwd = getcwd(); if (empty($contentFolderFromRoot)){ $contentFolderFromRoot = 'content'; } else { $contentFolderFromRoot = str_replace('\\','/',$contentFolderFromRoot); } if (!is_dir($cwd)){ throw new Exception("getcwd returned a path that is not a directory !"); } if (!is_dir("$cwd/$contentFolderFromRoot")){ $contentFolderFromRoot = 'vendor/picocms/pico/content-sample'; } if (substr($contentFolderFromRoot,-1) !== '/'){ $contentFolderFromRoot .= '/'; } // instance Pico $this->pico = new Pico( $cwd, // root dir $contentFolderFromRoot, // config dir self::PLUGINS_PATH, // plugins dir self::THEMES_PATH // themes dir ); $this->pico->loadPlugin(new SeacmsAppPlugin($this->pico, $testRunner)); $this->update_SERVERIfNeeded($this->pico, $contentFolderFromRoot); } public function runPico(): string { return $this->pico->run(); } /** * instanciate Pico and run it then echo output * @param string $contentFolderFromRoot where is the root folder */ public static function run(string $contentFolderFromRoot) { try { $app = new App($contentFolderFromRoot); $output = $app->runPico(); self::appendErrorMessagesIfNeeded($output); } catch (SpecialOutputException $th) { $output = $th->getJsonResponse()->send(); } catch (Throwable $th) { $output = << Exception : {$th->__toString()} HTML; self::appendErrorMessagesIfNeeded($output); } finally { echo $output; } } /** * append error messages from $GLOBALS['errorMessages'] * only if $_GET['debug'] === 'yes' * @param string &$output */ protected static function appendErrorMessagesIfNeeded(string &$output) { if (!empty($_GET['debug']) && $_GET['debug'] === 'yes' && !empty($GLOBALS['errorMessages'])){ $formattedMessages = implode("\n", $GLOBALS['errorMessages']); $formattedMessages = << $formattedMessages HTML; if (preg_match('/<\/body>/i', $output, $match)) { $output = str_replace($match[0], $formattedMessages.$match[0], $output); } else { $output = $output.$formattedMessages; } } } /** * detect if rewrite mode then update $_SERVER in consequence * @see Pico:evaluateRequestUrl() * * @param Pico $pico * @param string $configDir */ protected function update_SERVERIfNeeded(Pico $pico, string $configDir) { $continue = true; $requestUrl = $this->extractRequestUrlFormQueryString(); $data = [ 'page' => '', 'rootPath' => '/', 'baseFolder' => $configDir, 'nbLevels' => 0 ]; $this->extractFromRequestUrl($data,$configDir,$requestUrl,$continue) ->extractFromScriptName($data,$configDir,$continue) ->setUrl($data, $continue, $configDir, $pico); } /** * extract requestUrlFromQueryString * @return string $requestUrl */ protected function extractRequestUrlFormQueryString(): string { // use QUERY_STRING; e.g. /pico/?sub/page $pathComponent = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; if ($pathComponent) { $pathComponent = strstr($pathComponent, '&', true) ?: $pathComponent; if (strpos($pathComponent, '=') === false) { return trim(rawurldecode($pathComponent), '/'); } } return ''; } /** * test if wanted requestUrl is found * @param array &$data * @param string $configDir * @param string $requestUrl * @param bool &$continue * @return self * * set continue = false if found */ protected function extractFromRequestUrl(array &$data, string $configDir, string $requestUrl, bool &$continue): self { if ($continue && !empty($requestUrl)){ $supposedEndUrlForRewrite = $configDir.$requestUrl.'/index.php'; $supposedEndUrlForNotRewrite = $configDir.'index.php'; $matches = []; $configDirForMatch = preg_quote($configDir,'/'); if ($this->isServerEndedBy($supposedEndUrlForRewrite,'SCRIPT_NAME')){ $data['page'] = $requestUrl; $data['rootPath'] = substr($_SERVER['SCRIPT_NAME'],0,-strlen($supposedEndUrlForRewrite)); $data['nbLevels'] = count(explode('/',$configDir.$requestUrl)); $continue = false; } elseif ($this->isServerEndedBy($supposedEndUrlForNotRewrite,'SCRIPT_NAME')){ $data['page'] = $requestUrl; $data['nbLevels'] = count(explode('/',$configDir)) -1; $data['rootPath'] = substr($_SERVER['SCRIPT_NAME'],0,-strlen($supposedEndUrlForNotRewrite)); $continue = false; } elseif ($this->isServerEndedBy('index.php','SCRIPT_NAME') && !preg_match("/^(.*)$configDirForMatch(.*)index.php$/",$_SERVER['SCRIPT_NAME'],$matches) && !preg_match("/^(.*)\/sites\/(.*)index.php$/",$_SERVER['SCRIPT_NAME'],$matches)) { $data['page'] = $requestUrl; $data['nbLevels'] = 0; $data['rootPath'] = substr($_SERVER['SCRIPT_NAME'],0,-strlen('index.php')); $continue = false; } } return $this; } /** * test if SCRIPT_NAME contain url rewrite * @param array &$data * @param string $configDir * @param bool &$continue * @return self * * set continue = false if found */ protected function extractFromScriptName(array &$data, string $configDir, bool &$continue): self { if ($continue && !empty($_SERVER['SCRIPT_NAME']) && is_string($_SERVER['SCRIPT_NAME'])){ $matches = []; $configDirForMatch = preg_quote($configDir,'/'); if (preg_match("/^(.*)$configDirForMatch(.*)index.php$/",$_SERVER['SCRIPT_NAME'],$matches)){ $rootPath = $matches[1]; $requestUrl = !empty($matches[2]) ? (substr($matches[2],-1) == '/' ? substr($matches[2],0,-1) : $matches[2]) : ''; } } return $this; } /** * set SERVER QUERY_STRING * @param array $data * @param bool $continue * @param string $configDir * @param Pico $pico * @return $this */ protected function setUrl(array $data, bool $continue, string $configDir, Pico $pico): self { $config = [ 'rewrite_url' => false, 'themes_url' => self::THEMES_PATH, 'plugins_url' => self::PLUGINS_PATH, ]; // SCRIPT_NAME $rootPath = (empty($data['rootPath']) || !is_string($data['rootPath'])) ? '/' : ( (substr($data['rootPath'],-1) == '/') ? $data['rootPath'] : $data['rootPath'].'/' ); $_SERVER['SCRIPT_NAME'] = $rootPath.$configDir.'index.php'; $_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'].($_SERVER['PATH_INFO'] ?? ''); $_SERVER['DOCUMENT_URI'] = $_SERVER['PHP_SELF']; // QUERY_STRING $qString = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; if (substr($qString,0,strlen($data['page'])+1)==$data['page'].'&'){ $qString = substr($qString,strlen($data['page'])+1); } elseif ($qString == $data['page']){ $qString = ''; } if (!empty($data['page'])){ $qString = $data['page'].(empty($qString) ? '' : "&$qString"); } $_SERVER['QUERY_STRING'] = $qString; $_SERVER['REQUEST_URI'] = $_SERVER['DOCUMENT_URI'].(empty($_SERVER['QUERY_STRING'])?'':"?{$_SERVER['QUERY_STRING']}"); //FILENAME $cwd = getcwd(); $fn = str_replace('\\','/',realpath($cwd.'/'.$configDir.'index.php')); $_SERVER['SCRIPT_FILENAME'] = $fn; // config $config['rewrite_url'] = true; if ($nbLevels == 0){ $nbLevels = 1; } $previous = implode('',array_fill(0,$nbLevels,'../')); $config['themes_url'] = $previous.$config['themes_url']; $config['plugins_url'] = $previous.$config['plugins_url']; $pico->setConfig($config); $dataJSON = json_encode(compact(['data','continue','configDir','pathComponent','qString','cwd','fn','config'])); echo << console.log($dataJSON) HTML; return $this; } /** * test if $_SERVER[$key] end by $wantedValue * @param string $wantedValue * @param string $key * @return bool */ protected function isServerEndedBy(string $wantedValue, string $key): bool { return (!empty($_SERVER[$key]) && is_string($_SERVER[$key]) && substr($_SERVER[$key],-strlen($wantedValue)) == $wantedValue); } }