diff --git a/App.php b/App.php index 9045c2c..fe29d00 100644 --- a/App.php +++ b/App.php @@ -140,122 +140,177 @@ class App * @param string $configDir */ protected function update_SERVERIfNeeded(Pico $pico, string $configDir) - { - $continue = true; - $requestUrl = $this->extractRequestUrlFormQueryString(); + { $data = [ - 'page' => '', + 'FROM_QUERY_STRING' => '', + 'FROM_SCRIPT_NAME' => '', + 'FROM_SCRIPT_FILENAME' => '', 'rootPath' => '/', - 'baseFolder' => $configDir, - 'nbLevels' => 0 + 'rootPathFound' => false, + 'rewriteModeactivated' => false, + 'page' => 'index', + 'continue' => true ]; - - $this->extractFromRequestUrl($data,$configDir,$requestUrl,$continue) - ->extractFromScriptName($data,$configDir,$continue) - ->setUrl($data, $continue, $configDir, $pico); + $this + ->extractRequestUrlFormQueryString($data) + ->extractRequestUrlFromScriptFileName($data,$configDir) + ->extractRequestUrlFromScriptName($data,$configDir) + ->extractRootPathFromScriptNameIfNeeded($data,$configDir) + ->definePage($data) + ->setUrl($data, $configDir, $pico); } /** * extract requestUrlFromQueryString - * @return string $requestUrl + * @param array &$data + * @return self */ - 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), '/'); + 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 ''; + return $this; } /** - * test if wanted requestUrl is found + * extract requestUrlFromScriptName * @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 + protected function extractRequestUrlFromScriptName(array &$data, string $configDir): self { - if ($continue && !empty($requestUrl)){ - $supposedEndUrlForRewrite = $configDir.$requestUrl.'/index.php'; - $supposedEndUrlForNotRewrite = $configDir.'index.php'; + 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 ($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; + if (preg_match("/^(.*)$configDirForMatch(.*)index.php$/",$_SERVER['SCRIPT_NAME'],$matches)){ + $data['rootPath'] = $matches[1]; + $data['rootPathFound'] = true; + $data['FROM_SCRIPT_NAME'] = $this->formtStringWithLeadingSlash($matches[2],false); + } elseif (!empty($data['FROM_SCRIPT_FILENAME']) && $this->isServerEndedBy("{$data['FROM_SCRIPT_FILENAME']}/index.php",'SCRIPT_NAME')){ + $data['rootPath'] = $this->formtStringWithLeadingSlash($matches[2],false); + $data['rootPathFound'] = true; + $data['FROM_SCRIPT_NAME'] = $data['FROM_SCRIPT_FILENAME']; + $data['rewriteModeactivated'] = true; } } return $this; } /** - * test if SCRIPT_NAME contain url rewrite + * 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->formtStringWithLeadingSlash($formFileName,false); + } + } + } + return $this; + } + + /** + * extract rootPath from ScriptName * @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 + protected function extractRootPathFromScriptNameIfNeeded(array &$data, string $configDir): self { - if ($continue && !empty($_SERVER['SCRIPT_NAME']) && is_string($_SERVER['SCRIPT_NAME'])){ + if ($data['continue'] && !$data['rootPathFound']){ + // use SCRIPT_NAME; e.g. /subfolder/index.php $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]) : ''; + $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->formtStringWithLeadingSlash($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 formtStringWithLeadingSlash(?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 bool $continue * @param string $configDir * @param Pico $pico * @return $this */ - protected function setUrl(array $data, bool $continue, string $configDir, Pico $pico): self + protected function setUrl(array $data, string $configDir, Pico $pico): self { - $config = [ - 'rewrite_url' => false, - 'themes_url' => self::THEMES_PATH, - 'plugins_url' => self::PLUGINS_PATH, - ]; - + $bfserver = $_SERVER; // 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'; + $rootPath = (empty($data['rootPath']) || !is_string($data['rootPath'])) ? '/' : $this->formtStringWithLeadingSlash($data['rootPath'],true); + if (!$data['rewriteModeactivated'] && $rootPath == '/' && $data['page'] == 'index' && $_SERVER['SCRIPT_NAME'] == '/index.php'){ + echo json_encode($data); + } + $_SERVER['SCRIPT_NAME'] = $rootPath.($data['rewriteModeactivated']?'':$configDir).'index.php'; $_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'].($_SERVER['PATH_INFO'] ?? ''); $_SERVER['DOCUMENT_URI'] = $_SERVER['PHP_SELF']; @@ -273,27 +328,31 @@ class App $_SERVER['QUERY_STRING'] = $qString; $_SERVER['REQUEST_URI'] = $_SERVER['DOCUMENT_URI'].(empty($_SERVER['QUERY_STRING'])?'':"?{$_SERVER['QUERY_STRING']}"); - //FILENAME + //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; - 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']; + $config['configDir'] = $this->formtStringWithLeadingSlash($configDir,false); + $config['content_dir'] = $this->formtStringWithLeadingSlash($configDir,false); + $config['themes_url'] = "$baseUrl$rootPath".self::THEMES_PATH; + $config['plugins_url'] = "$baseUrl$rootPath".self::PLUGINS_PATH; $pico->setConfig($config); - $dataJSON = json_encode(compact(['data','continue','configDir','pathComponent','qString','cwd','fn','config'])); - echo << - console.log($dataJSON) - - HTML; + $server = $_SERVER; + $dataJSON = json_encode(compact(['data','configDir','qString','cwd','fn','config','server','bfserver'])); + // echo << + // console.log($dataJSON) + // + // HTML; + // if ($configDir == 'content/' && $data['rewriteModeactivated'] && $data['page'] == 'index' && $rootPath == '/'){ + // echo $dataJSON; + // } return $this; } @@ -307,4 +366,21 @@ class App { 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->formtStringWithLeadingSlash($pico->getBaseUrl(),true); + + if (substr($baseUrl,-strlen($rootPath.$configDir)) == $rootPath.$configDir){ + $baseUrl = substr($baseUrl,0,-strlen($rootPath.$configDir)); + } + return $this->formtStringWithLeadingSlash($baseUrl,false); + } } \ No newline at end of file diff --git a/tests/AppTest.php b/tests/AppTest.php index 078b193..fca6105 100644 --- a/tests/AppTest.php +++ b/tests/AppTest.php @@ -85,10 +85,11 @@ final class AppTest extends TestCase { } catch (Throwable $th){ } + $sn = $_SERVER['SCRIPT_NAME']; $cwd = getcwd(); $this->revertSERVER(); $this->assertTrue($thrown,"TestBaseUrlException not found"); - $this->assertEquals($waitedBaseUrl,$foundTh->getBaseUrl(),"Not same baseUrl"); + $this->assertEquals($waitedBaseUrl,$foundTh->getBaseUrl(),"Not same baseUrl ($sn)"); $this->assertEquals("$cwd/vendor/picocms/plugins/",$foundTh->getPluginDir(),"Not same pluginDir"); $this->assertEquals("$cwd/vendor/picocms/themes/",$foundTh->getThemeDir(),"Not same themeDir"); $this->assertEquals("$cwd/",$foundTh->getRootDir(),"Not same rootDir"); @@ -156,12 +157,15 @@ final class AppTest extends TestCase { $scriptNameMiddle = empty($queryData['s']) ? '' : $queryData['s'].'/'; foreach (['','index.php'] as $endScriptName) { $formattedQueryString = str_replace('/','%2F',$queryString); - $pageUrl = empty($queryData['s']) ? (empty($queryData['q']) ? '' : $formattedQueryString) : $queryData['s']; + if (substr($formattedQueryString,0,1)){ + $formattedQueryString = substr($formattedQueryString,1); + } + $pageUrl = (empty($queryData['s']) && empty($queryData['q'])) ? '' : $pageIdInUrl; $canRewriteFromRoot = empty($queryData['s']) && empty($queryData['f']); if ($rootFolder == 'content' && $canRewriteFromRoot){ $scriptName = "$baseScriptName/$scriptNameMiddle$endScriptName"; $name = $rootFolder.$scriptName.$queryString.'*'; - $this->prepareData($data,$name,$rootFolder,'index.php',$scriptName,$queryData['q'],$baseUrl,$pageId,$pageUrl); + $this->prepareData($baseUrl,$data,$name,$rootFolder,'index.php',$scriptName,$queryData['q'],$baseUrl.'content/',$pageId,$pageUrl); } foreach ([false,true] as $withRewrite) { if ($withRewrite){ @@ -174,16 +178,17 @@ final class AppTest extends TestCase { $waitedUrl = $baseUrl.$rootFolder.'/'; } if ($canRewriteFromRoot){ - $this->prepareData($data,$name."*",$rootFolder,"index.php",$scriptName,$queryData['q'],$waitedUrl,$pageId,$pageUrl); + $this->prepareData($baseUrl,$data,$name."*",$rootFolder,"index.php",$scriptName,$queryData['q'],$waitedUrl,$pageId,$pageUrl); } $formattedRootMiddle = empty($pageIdInUrl) ? '' : "/$pageIdInUrl"; - $this->prepareData($data,$name,$rootFolder,"$rootFolder$formattedRootMiddle/index.php",$scriptName,$queryData['q'],$waitedUrl,$pageId,$pageUrl); + $this->prepareData($baseUrl,$data,$name,$rootFolder,"$rootFolder$formattedRootMiddle/index.php",$scriptName,$queryData['q'],$waitedUrl,$pageId,$pageUrl); } } } } protected function prepareData( + string $baseUrl, array &$data, string $name, string $rootFolder, @@ -196,13 +201,8 @@ final class AppTest extends TestCase { ) { $waitedPageUrl = $waitedBaseUrl.$waitedPageEndUrl; - $nbLevels = in_array($shortScriptName,['/','/index.php']) ? 0 : count(explode('/',$rootFolder)); - $prefix = implode('/',array_fill(0,$nbLevels,'..')); - if (!empty($prefix)){ - $prefix .= '/'; - } - $waitedThemesUrl = $waitedBaseUrl.$prefix.'vendor/picocms/themes'; - $waitedPluginsUrl = $waitedBaseUrl.$prefix.'vendor/picocms/plugins'; + $waitedThemesUrl = $baseUrl.'vendor/picocms/themes'; + $waitedPluginsUrl = $baseUrl.'vendor/picocms/plugins'; $data[$name] = compact([ 'rootFolder', 'filePath', @@ -294,9 +294,10 @@ final class AppTest extends TestCase { $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // forced $_SERVER['REMOTE_PORT'] = '80'; // forced $_SERVER['SERVER_ADDR'] = '127.0.0.1'; // forced - $_SERVER['SERVER_ADDR'] = '80'; // forced + $_SERVER['SERVER_PORT'] = '80'; // forced $_SERVER['SERVER_NAME'] = 'localhost'; // forced $_SERVER['HTTPS'] = null; // forced + $_SERVER['REQUEST_TIME'] = time(); } }