dufraissejeremy 2 years ago
parent 26db1a236d
commit 25152ec419
  1. 242
      App.php
  2. 27
      tests/AppTest.php

@ -140,122 +140,177 @@ class App
* @param string $configDir * @param string $configDir
*/ */
protected function update_SERVERIfNeeded(Pico $pico, string $configDir) protected function update_SERVERIfNeeded(Pico $pico, string $configDir)
{ {
$continue = true;
$requestUrl = $this->extractRequestUrlFormQueryString();
$data = [ $data = [
'page' => '', 'FROM_QUERY_STRING' => '',
'FROM_SCRIPT_NAME' => '',
'FROM_SCRIPT_FILENAME' => '',
'rootPath' => '/', 'rootPath' => '/',
'baseFolder' => $configDir, 'rootPathFound' => false,
'nbLevels' => 0 'rewriteModeactivated' => false,
'page' => 'index',
'continue' => true
]; ];
$this
$this->extractFromRequestUrl($data,$configDir,$requestUrl,$continue) ->extractRequestUrlFormQueryString($data)
->extractFromScriptName($data,$configDir,$continue) ->extractRequestUrlFromScriptFileName($data,$configDir)
->setUrl($data, $continue, $configDir, $pico); ->extractRequestUrlFromScriptName($data,$configDir)
->extractRootPathFromScriptNameIfNeeded($data,$configDir)
->definePage($data)
->setUrl($data, $configDir, $pico);
} }
/** /**
* extract requestUrlFromQueryString * extract requestUrlFromQueryString
* @return string $requestUrl * @param array &$data
* @return self
*/ */
protected function extractRequestUrlFormQueryString(): string protected function extractRequestUrlFormQueryString(array &$data): self
{ {
// use QUERY_STRING; e.g. /pico/?sub/page if ($data['continue']){
$pathComponent = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; // use QUERY_STRING; e.g. ?sub/page
if ($pathComponent) { $qString = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
$pathComponent = strstr($pathComponent, '&', true) ?: $pathComponent; if ($qString) {
if (strpos($pathComponent, '=') === false) { $qString = strstr($qString, '&', true) ?: $qString;
return trim(rawurldecode($pathComponent), '/'); if (strpos($qString, '=') === false) {
$data['FROM_QUERY_STRING'] = $qString;
}
} }
} }
return ''; return $this;
} }
/** /**
* test if wanted requestUrl is found * extract requestUrlFromScriptName
* @param array &$data * @param array &$data
* @param string $configDir * @param string $configDir
* @param string $requestUrl
* @param bool &$continue
* @return self * @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)){ if ($data['continue'] && !empty($_SERVER['SCRIPT_NAME']) && is_string($_SERVER['SCRIPT_NAME'])){
$supposedEndUrlForRewrite = $configDir.$requestUrl.'/index.php'; // use SCRIPT_NAME; e.g. /subfolder/content/sub/page/index.php
$supposedEndUrlForNotRewrite = $configDir.'index.php';
$matches = []; $matches = [];
$configDirForMatch = preg_quote($configDir,'/'); $configDirForMatch = preg_quote($configDir,'/');
if ($this->isServerEndedBy($supposedEndUrlForRewrite,'SCRIPT_NAME')){ if (preg_match("/^(.*)$configDirForMatch(.*)index.php$/",$_SERVER['SCRIPT_NAME'],$matches)){
$data['page'] = $requestUrl; $data['rootPath'] = $matches[1];
$data['rootPath'] = substr($_SERVER['SCRIPT_NAME'],0,-strlen($supposedEndUrlForRewrite)); $data['rootPathFound'] = true;
$data['nbLevels'] = count(explode('/',$configDir.$requestUrl)); $data['FROM_SCRIPT_NAME'] = $this->formtStringWithLeadingSlash($matches[2],false);
$continue = false; } elseif (!empty($data['FROM_SCRIPT_FILENAME']) && $this->isServerEndedBy("{$data['FROM_SCRIPT_FILENAME']}/index.php",'SCRIPT_NAME')){
} elseif ($this->isServerEndedBy($supposedEndUrlForNotRewrite,'SCRIPT_NAME')){ $data['rootPath'] = $this->formtStringWithLeadingSlash($matches[2],false);
$data['page'] = $requestUrl; $data['rootPathFound'] = true;
$data['nbLevels'] = count(explode('/',$configDir)) -1; $data['FROM_SCRIPT_NAME'] = $data['FROM_SCRIPT_FILENAME'];
$data['rootPath'] = substr($_SERVER['SCRIPT_NAME'],0,-strlen($supposedEndUrlForNotRewrite)); $data['rewriteModeactivated'] = true;
$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; 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 array &$data
* @param string $configDir * @param string $configDir
* @param bool &$continue
* @return self * @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 = []; $matches = [];
$configDirForMatch = preg_quote($configDir,'/'); $wantedPage = empty($data['FROM_SCRIPT_FILENAME']) ? '' : $data['FROM_SCRIPT_FILENAME'];
if (preg_match("/^(.*)$configDirForMatch(.*)index.php$/",$_SERVER['SCRIPT_NAME'],$matches)){ $wantedPageQuoted = preg_quote($wantedPage,'/');
$rootPath = $matches[1]; if (preg_match("/^(.*){$wantedPageQuoted}\/index.php$/",$_SERVER['SCRIPT_NAME'],$matches)){
$requestUrl = !empty($matches[2]) ? (substr($matches[2],-1) == '/' ? substr($matches[2],0,-1) : $matches[2]) : ''; $data['rootPath'] = $this->formtStringWithLeadingSlash($matches[1],true);
$data['rootPathFound'] = true;
$data['rewriteModeactivated'] = (realpath($_SERVER['SCRIPT_FILENAME']) == realpath(getcwd()."/{$configDir}index.php"));
} }
} }
return $this; 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 * set SERVER QUERY_STRING
* @param array $data * @param array $data
* @param bool $continue
* @param string $configDir * @param string $configDir
* @param Pico $pico * @param Pico $pico
* @return $this * @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 = [ $bfserver = $_SERVER;
'rewrite_url' => false,
'themes_url' => self::THEMES_PATH,
'plugins_url' => self::PLUGINS_PATH,
];
// SCRIPT_NAME // SCRIPT_NAME
$rootPath = (empty($data['rootPath']) || !is_string($data['rootPath'])) ? '/' : ( $rootPath = (empty($data['rootPath']) || !is_string($data['rootPath'])) ? '/' : $this->formtStringWithLeadingSlash($data['rootPath'],true);
(substr($data['rootPath'],-1) == '/') if (!$data['rewriteModeactivated'] && $rootPath == '/' && $data['page'] == 'index' && $_SERVER['SCRIPT_NAME'] == '/index.php'){
? $data['rootPath'] echo json_encode($data);
: $data['rootPath'].'/' }
); $_SERVER['SCRIPT_NAME'] = $rootPath.($data['rewriteModeactivated']?'':$configDir).'index.php';
$_SERVER['SCRIPT_NAME'] = $rootPath.$configDir.'index.php';
$_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'].($_SERVER['PATH_INFO'] ?? ''); $_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'].($_SERVER['PATH_INFO'] ?? '');
$_SERVER['DOCUMENT_URI'] = $_SERVER['PHP_SELF']; $_SERVER['DOCUMENT_URI'] = $_SERVER['PHP_SELF'];
@ -273,27 +328,31 @@ class App
$_SERVER['QUERY_STRING'] = $qString; $_SERVER['QUERY_STRING'] = $qString;
$_SERVER['REQUEST_URI'] = $_SERVER['DOCUMENT_URI'].(empty($_SERVER['QUERY_STRING'])?'':"?{$_SERVER['QUERY_STRING']}"); $_SERVER['REQUEST_URI'] = $_SERVER['DOCUMENT_URI'].(empty($_SERVER['QUERY_STRING'])?'':"?{$_SERVER['QUERY_STRING']}");
//FILENAME //SCRIPT_FILENAME
$cwd = getcwd(); $cwd = getcwd();
$fn = str_replace('\\','/',realpath($cwd.'/'.$configDir.'index.php')); $fn = str_replace('\\','/',realpath($cwd.'/'.$configDir.'index.php'));
$_SERVER['SCRIPT_FILENAME'] = $fn; $_SERVER['SCRIPT_FILENAME'] = $fn;
// config // config
$baseUrl = $this->getBaseUrl($rootPath,$configDir,$pico);
$config = $pico->getConfig();
$config['rewrite_url'] = true; $config['rewrite_url'] = true;
if ($nbLevels == 0){ $config['configDir'] = $this->formtStringWithLeadingSlash($configDir,false);
$nbLevels = 1; $config['content_dir'] = $this->formtStringWithLeadingSlash($configDir,false);
} $config['themes_url'] = "$baseUrl$rootPath".self::THEMES_PATH;
$previous = implode('',array_fill(0,$nbLevels,'../')); $config['plugins_url'] = "$baseUrl$rootPath".self::PLUGINS_PATH;
$config['themes_url'] = $previous.$config['themes_url'];
$config['plugins_url'] = $previous.$config['plugins_url'];
$pico->setConfig($config); $pico->setConfig($config);
$dataJSON = json_encode(compact(['data','continue','configDir','pathComponent','qString','cwd','fn','config'])); $server = $_SERVER;
echo <<<HTML $dataJSON = json_encode(compact(['data','configDir','qString','cwd','fn','config','server','bfserver']));
<script> // echo <<<HTML
console.log($dataJSON) // <script>
</script> // console.log($dataJSON)
HTML; // </script>
// HTML;
// if ($configDir == 'content/' && $data['rewriteModeactivated'] && $data['page'] == 'index' && $rootPath == '/'){
// echo $dataJSON;
// }
return $this; return $this;
} }
@ -307,4 +366,21 @@ class App
{ {
return (!empty($_SERVER[$key]) && is_string($_SERVER[$key]) && substr($_SERVER[$key],-strlen($wantedValue)) == $wantedValue); 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);
}
} }

@ -85,10 +85,11 @@ final class AppTest extends TestCase {
} catch (Throwable $th){ } catch (Throwable $th){
} }
$sn = $_SERVER['SCRIPT_NAME'];
$cwd = getcwd(); $cwd = getcwd();
$this->revertSERVER(); $this->revertSERVER();
$this->assertTrue($thrown,"TestBaseUrlException not found"); $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/plugins/",$foundTh->getPluginDir(),"Not same pluginDir");
$this->assertEquals("$cwd/vendor/picocms/themes/",$foundTh->getThemeDir(),"Not same themeDir"); $this->assertEquals("$cwd/vendor/picocms/themes/",$foundTh->getThemeDir(),"Not same themeDir");
$this->assertEquals("$cwd/",$foundTh->getRootDir(),"Not same rootDir"); $this->assertEquals("$cwd/",$foundTh->getRootDir(),"Not same rootDir");
@ -156,12 +157,15 @@ final class AppTest extends TestCase {
$scriptNameMiddle = empty($queryData['s']) ? '' : $queryData['s'].'/'; $scriptNameMiddle = empty($queryData['s']) ? '' : $queryData['s'].'/';
foreach (['','index.php'] as $endScriptName) { foreach (['','index.php'] as $endScriptName) {
$formattedQueryString = str_replace('/','%2F',$queryString); $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']); $canRewriteFromRoot = empty($queryData['s']) && empty($queryData['f']);
if ($rootFolder == 'content' && $canRewriteFromRoot){ if ($rootFolder == 'content' && $canRewriteFromRoot){
$scriptName = "$baseScriptName/$scriptNameMiddle$endScriptName"; $scriptName = "$baseScriptName/$scriptNameMiddle$endScriptName";
$name = $rootFolder.$scriptName.$queryString.'*'; $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) { foreach ([false,true] as $withRewrite) {
if ($withRewrite){ if ($withRewrite){
@ -174,16 +178,17 @@ final class AppTest extends TestCase {
$waitedUrl = $baseUrl.$rootFolder.'/'; $waitedUrl = $baseUrl.$rootFolder.'/';
} }
if ($canRewriteFromRoot){ 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"; $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( protected function prepareData(
string $baseUrl,
array &$data, array &$data,
string $name, string $name,
string $rootFolder, string $rootFolder,
@ -196,13 +201,8 @@ final class AppTest extends TestCase {
) )
{ {
$waitedPageUrl = $waitedBaseUrl.$waitedPageEndUrl; $waitedPageUrl = $waitedBaseUrl.$waitedPageEndUrl;
$nbLevels = in_array($shortScriptName,['/','/index.php']) ? 0 : count(explode('/',$rootFolder)); $waitedThemesUrl = $baseUrl.'vendor/picocms/themes';
$prefix = implode('/',array_fill(0,$nbLevels,'..')); $waitedPluginsUrl = $baseUrl.'vendor/picocms/plugins';
if (!empty($prefix)){
$prefix .= '/';
}
$waitedThemesUrl = $waitedBaseUrl.$prefix.'vendor/picocms/themes';
$waitedPluginsUrl = $waitedBaseUrl.$prefix.'vendor/picocms/plugins';
$data[$name] = compact([ $data[$name] = compact([
'rootFolder', 'rootFolder',
'filePath', 'filePath',
@ -294,9 +294,10 @@ final class AppTest extends TestCase {
$_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // forced $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // forced
$_SERVER['REMOTE_PORT'] = '80'; // forced $_SERVER['REMOTE_PORT'] = '80'; // forced
$_SERVER['SERVER_ADDR'] = '127.0.0.1'; // 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['SERVER_NAME'] = 'localhost'; // forced
$_SERVER['HTTPS'] = null; // forced $_SERVER['HTTPS'] = null; // forced
$_SERVER['REQUEST_TIME'] = time();
} }
} }

Loading…
Cancel
Save