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) { $data = [ 'FROM_QUERY_STRING' => '', 'FROM_SCRIPT_NAME' => '', 'FROM_SCRIPT_FILENAME' => '', 'rootPath' => '/', 'rootPathFound' => false, 'rewriteModeactivated' => false, 'page' => 'index', 'continue' => true ]; $this ->extractRequestUrlFormQueryString($data) ->extractRequestUrlFromScriptFileName($data,$configDir) ->extractRequestUrlFromScriptName($data,$configDir) ->extractRootPathFromScriptNameIfNeeded($data,$configDir) ->definePage($data) ->setUrl($data, $configDir, $pico); } /** * extract requestUrlFromQueryString * @param array &$data * @return self */ protected function extractRequestUrlFormQueryString(array &$data): self { if ($data['continue']){ // use QUERY_STRING; e.g. ?sub/page $qString = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; if ($qString) { $qString = strstr($qString, '&', true) ?: $qString; if (strpos($qString, '=') === false) { $data['FROM_QUERY_STRING'] = $qString; } } } return $this; } /** * extract requestUrlFromScriptName * @param array &$data * @param string $configDir * @return self */ protected function extractRequestUrlFromScriptName(array &$data, string $configDir): self { if ($data['continue'] && !empty($_SERVER['SCRIPT_NAME']) && is_string($_SERVER['SCRIPT_NAME'])){ // use SCRIPT_NAME; e.g. /subfolder/content/sub/page/index.php $matches = []; $configDirForMatch = preg_quote($configDir,'/'); if (preg_match("/^(.*)$configDirForMatch(.*)(?!.php)(?:index.php)?$/",$_SERVER['SCRIPT_NAME'],$matches)){ $data['rootPath'] = $matches[1]; $data['rootPathFound'] = true; $data['FROM_SCRIPT_NAME'] = $this->formatStringWithLeadingSlash($matches[2],false); } elseif (!empty($data['FROM_SCRIPT_FILENAME']) && ( $this->isServerEndedBy("{$data['FROM_SCRIPT_FILENAME']}/index.php",'SCRIPT_NAME') || $this->isServerEndedBy("{$data['FROM_SCRIPT_FILENAME']}/",'SCRIPT_NAME') ) ){ $data['rootPath'] = $this->formatStringWithLeadingSlash($matches[2],false); $data['rootPathFound'] = true; $data['FROM_SCRIPT_NAME'] = $data['FROM_SCRIPT_FILENAME']; $data['rewriteModeactivated'] = true; } } return $this; } /** * extract requestUrlFromScriptFileName * @param array &$data * @param string $configDir * @return self */ protected function extractRequestUrlFromScriptFileName(array &$data, string $configDir): self { if ($data['continue'] && !empty($_SERVER['SCRIPT_FILENAME']) && is_string($_SERVER['SCRIPT_FILENAME']) && substr($_SERVER['SCRIPT_FILENAME'],-strlen('index.php')) == 'index.php'){ // use SCRIPT_FILENAME; e.g. /var/www/subfolder/content/sub/page/index.php // check if the current folder seems to correspond to root folder of seacms if (is_dir('content') && is_dir('sites') && is_file('index.php')){ $cwd = realpath(getcwd()); $truncatedFileName = substr(realpath($_SERVER['SCRIPT_FILENAME']),strlen($cwd)); $matches = []; $configDirForMatch1 = preg_quote($configDir,'/'); $configDirForMatch2 = preg_quote(str_replace('/','\\',$configDir),'/'); if (preg_match("/^(.*)(?:$configDirForMatch1|$configDirForMatch2)(.*)index.php$/",$_SERVER['SCRIPT_FILENAME'],$matches)){ $formFileName = str_replace('\\','/',$matches[2]); $data['FROM_SCRIPT_FILENAME'] = $this->formatStringWithLeadingSlash($formFileName,false); } } } return $this; } /** * extract rootPath from ScriptName * @param array &$data * @param string $configDir * @return self */ protected function extractRootPathFromScriptNameIfNeeded(array &$data, string $configDir): self { if ($data['continue'] && !$data['rootPathFound']){ // use SCRIPT_NAME; e.g. /subfolder/index.php $matches = []; $wantedPage = empty($data['FROM_SCRIPT_FILENAME']) ? '' : $data['FROM_SCRIPT_FILENAME']; $wantedPageQuoted = preg_quote($wantedPage,'/'); if (preg_match("/^(.*){$wantedPageQuoted}\/(?:index.php)?$/",$_SERVER['SCRIPT_NAME'],$matches)){ $data['rootPath'] = $this->formatStringWithLeadingSlash($matches[1],true); $data['rootPathFound'] = true; $data['rewriteModeactivated'] = (realpath($_SERVER['SCRIPT_FILENAME']) == realpath(getcwd()."/{$configDir}index.php")); } } return $this; } /** * format string with leading '/' * @param null|string $rawString * @param bool $withLeadingSlash * @return string $page */ protected function formatStringWithLeadingSlash(?string $rawString, bool $withLeadingSlash = false): string { return $withLeadingSlash ? (!empty($rawString) ? (substr($rawString,-1) == '/' ? $rawString : $rawString.'/') : '/') : (!empty($rawString) ? (substr($rawString,-1) == '/' ? substr($rawString,0,-1) : $rawString) : ''); } /** * define page * @param array $data * @return $this */ protected function definePage(array &$data): self { if ($data['continue']){ $data['page'] = !empty($data['FROM_QUERY_STRING']) ? $data['FROM_QUERY_STRING'] : ( !empty($data['FROM_SCRIPT_NAME']) ? $data['FROM_SCRIPT_NAME'] : ( !empty($data['FROM_SCRIPT_FILENAME']) ? $data['FROM_SCRIPT_FILENAME'] : 'index' ) ); } return $this; } /** * set SERVER QUERY_STRING * @param array $data * @param string $configDir * @param Pico $pico * @return $this */ protected function setUrl(array $data, string $configDir, Pico $pico): self { $bfserver = $_SERVER; // SCRIPT_NAME $rootPath = (empty($data['rootPath']) || !is_string($data['rootPath'])) ? '/' : $this->formatStringWithLeadingSlash($data['rootPath'],true); $_SERVER['SCRIPT_NAME'] = $rootPath.($data['rewriteModeactivated']?'':$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']}"); //SCRIPT_FILENAME $cwd = getcwd(); $fn = str_replace('\\','/',realpath($cwd.'/'.$configDir.'index.php')); $_SERVER['SCRIPT_FILENAME'] = $fn; // config $baseUrl = $this->getBaseUrl($rootPath,$configDir,$pico); $config = $pico->getConfig(); $config['rewrite_url'] = true; $config['configDir'] = $this->formatStringWithLeadingSlash($configDir,false); $config['content_dir'] = $this->formatStringWithLeadingSlash($configDir,false); $config['themes_url'] = "$baseUrl$rootPath".self::THEMES_PATH; $config['plugins_url'] = "$baseUrl$rootPath".self::PLUGINS_PATH; $pico->setConfig($config); $server = $_SERVER; $dataJSON = json_encode(compact(['data','configDir','qString','cwd','fn','config','server','bfserver'])); // 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); } /** * generate Base Url * @param string $rootPath * @param string $configDir * @param Pico $pico * @return string */ protected function getBaseUrl(string $rootPath,string $configDir, Pico $pico): string { $baseUrl = $this->formatStringWithLeadingSlash($pico->getBaseUrl(),true); if (substr($baseUrl,-strlen($rootPath.$configDir)) == $rootPath.$configDir){ $baseUrl = substr($baseUrl,0,-strlen($rootPath.$configDir)); } return $this->formatStringWithLeadingSlash($baseUrl,false); } }