assertTrue($displayErrors); } /** * @depends testInit * @dataProvider apiRewriteProvider * @covers App::update_SERVERIfNeeded * @param string $rootFolder * @param string $filePath * @param string $shortScriptName * @param string $queryString * @param string $waitedBaseUrl * @param string $waitedPageId * @param string $waitedPageUrl * @param string $waitedThemesUrl * @param string $waitedPluginsUrl */ public function testApiRewrite( string $rootFolder, string $filePath, string $shortScriptName, string $queryString, string $waitedBaseUrl, string $waitedPageId, string $waitedPageUrl, string $waitedThemesUrl, string $waitedPluginsUrl, ): void { $this->saveSERVER(); $this->defineServer( true, $filePath, $shortScriptName, $queryString ); $app = new App($rootFolder,new TestBaseUrl()); $thrown = false; $foundTh = null; try { $output = $app->runPico(); } catch (TestBaseUrlException $th) { $thrown = true; $foundTh = $th; } 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 ($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"); $currentPage = $foundTh->getcurrentPage(); $this->assertIsArray($currentPage,"Current Page should be an array"); $this->assertArrayHasKey('id',$currentPage,"Current Page should be an array with key 'id'"); $this->assertEquals($waitedPageId,$currentPage['id'],"Not waited page's id"); $this->assertArrayHasKey('url',$currentPage,"Current Page should be an array with key 'url'"); $this->assertEquals($waitedPageUrl,$currentPage['url'],"Not waited page's url"); $twigVariables = $foundTh->getTwigVariables(); $this->assertIsArray($twigVariables,"Twigvariables should be an array"); $this->assertArrayHasKey('themes_url',$twigVariables,"Twigvariables should be an array with key 'themes_url'"); $this->assertEquals($waitedThemesUrl,$twigVariables['themes_url'],"Not waited themes_url"); $this->assertArrayHasKey('plugins_url',$twigVariables,"Twigvariables should be an array with key 'plugins_url'"); $this->assertEquals($waitedPluginsUrl,$twigVariables['plugins_url'],"Not waited plugins_url"); } public function apiRewriteProvider() { $data = []; $this->prepareAPage($data,'','content','index'); $this->prepareAPage($data,'','content','sub/index'); $this->prepareAPage($data,'','content','theme'); $this->prepareAPage($data,'','sites/default','index'); $this->prepareAPage($data,'','sites/default','sub/index'); $this->prepareAPage($data,'','sites/default','theme'); $this->prepareAPage($data,'/sea','content','index'); $this->prepareAPage($data,'/sea','content','sub/index'); $this->prepareAPage($data,'/sea','content','theme'); $this->prepareAPage($data,'/sea','sites/default','index'); $this->prepareAPage($data,'/sea','sites/default','sub/index'); $this->prepareAPage($data,'/sea','sites/default','theme'); // echo "\n"; // foreach($data as $name => $line){ // echo "$name => ".implode(',',$line)."\n"; // } return $data; } protected function prepareAPage( array &$data, string $baseScriptName, string $rootFolder, string $pageId ) { $baseUrl = 'http://localhost'.$baseScriptName.'/'; $isIndex = ($pageId == 'index'); $isSubIndex = (substr($pageId,-strlen('/index')) == '/index'); $pageIdInUrl = $isIndex ? '' : ($isSubIndex ? substr($pageId,0,-strlen('/index')) : $pageId) ; $queriesStrings = $isIndex ? [['q'=>'','s'=>'','f'=>'']] : [ ['q'=>$pageIdInUrl,'s'=>'','f'=>''], ['q'=>'','s'=>$pageIdInUrl,'f'=>''], ['q'=>'','s'=>$pageIdInUrl,'f'=>$pageIdInUrl], ['q'=>$pageIdInUrl,'s'=>$pageIdInUrl,'f'=>''], ['q'=>$pageIdInUrl,'s'=>$pageIdInUrl,'f'=>$pageIdInUrl] ]; foreach ($queriesStrings as $queryData) { $queryString = empty($queryData['q']) ? '' :'?'.$queryData['q']; $scriptNameMiddle = empty($queryData['s']) ? '' : $queryData['s'].'/'; foreach (['','index.php'] as $endScriptName) { $formattedQueryString = str_replace('/','%2F',$queryString); 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($baseUrl,$data,$name,$rootFolder,'index.php',$scriptName,$queryData['q'],$baseUrl.'content/',$pageId,$pageUrl); } foreach ([false,true] as $withRewrite) { if ($withRewrite){ $scriptName = "$baseScriptName/$scriptNameMiddle$endScriptName"; $name = $rootFolder.$scriptName.$queryString.' R'; $waitedUrl = $baseUrl; } else { $scriptName = "$baseScriptName/$rootFolder/$scriptNameMiddle$endScriptName"; $name = $rootFolder.$scriptName.$queryString; $waitedUrl = $baseUrl.$rootFolder.'/'; } if ($canRewriteFromRoot){ $this->prepareData($baseUrl,$data,$name."*",$rootFolder,"index.php",$scriptName,$queryData['q'],$waitedUrl,$pageId,$pageUrl); } $formattedRootMiddle = empty($pageIdInUrl) ? '' : "/$pageIdInUrl"; $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, string $filePath, string $shortScriptName, string $queryString, string $waitedBaseUrl, string $waitedPageId, string $waitedPageEndUrl ) { $waitedPageUrl = $waitedBaseUrl.$waitedPageEndUrl; $waitedThemesUrl = $baseUrl.'vendor/picocms/themes'; $waitedPluginsUrl = $baseUrl.'vendor/picocms/plugins'; $data[$name] = compact([ 'rootFolder', 'filePath', 'shortScriptName', 'queryString', 'waitedBaseUrl', 'waitedPageId', 'waitedPageUrl', 'waitedThemesUrl', 'waitedPluginsUrl' ]); } /** * define $_SERVER because fastcgi not run in CLI * @param bool $reset reset previous $_SERVER * @param string $filePath realpath of current script file * @param string $shortScriptName uri path of current script file * @param string $queryString wanted query string * @param string $method * @param string $pathInfo */ public function defineServer( bool $reset, string $filePath, string $shortScriptName, string $queryString, string $method = 'GET', string $pathInfo = '' ) { if (is_file($filePath)){ if (!is_array($_SERVER) || $reset){ $new = []; if (is_array($_SERVER)){ foreach(['SERVER_SOFTWARE','SERVER_PROTOCOL','GATEWAY_INTERFACE'] as $key){ if (array_key_exists($key,$_SERVER)){ $new[$key] = $_SERVER[$key]; } } } $_SERVER = $new; } $_SERVER['QUERY_STRING'] = $queryString; $_SERVER['REQUEST_METHOD'] = in_array($method,['GET','POST','PUT','DELETE','HEAD']) ? $method : 'GET'; // $_SERVER['CONTENT_TYPE'] = 'not defined'; // $_SERVER['CONTENT_LENGTH'] = 'not defined'; $documentRoot = dirname(realpath($filePath)); $fileName = basename(realpath($filePath)); $documentRootShort = (substr($documentRoot,-strlen(DIRECTORY_SEPARATOR)) != DIRECTORY_SEPARATOR) ? $documentRoot : substr($documentRoot,0,-strlen(DIRECTORY_SEPARATOR)); $documentRootFull = $documentRootShort.DIRECTORY_SEPARATOR; $scriptName = (basename($shortScriptName) == $fileName) ? $shortScriptName : $shortScriptName.((empty($shortScriptName) || substr($shortScriptName,-1) == '/') ? '' : '/').$fileName; $hashPos = strpos($queryString,'#'); $queryStringWithoutHash = (empty($queryString) || ($hashPos === 0)) ? '' : ( ($hashPos === false) ? "?$queryString" : '?'.sustr($queryString,0,$hashPos+1) ); $_SERVER['SCRIPT_FILENAME'] = $documentRootFull.$fileName; $_SERVER['SCRIPT_NAME'] = $scriptName; $_SERVER['PHP_SELF'] = $scriptName.$pathInfo; $_SERVER['PATH_INFO'] = $pathInfo; $_SERVER['ORIG_PATH_INFO'] = $pathInfo; $_SERVER['PATH_TRANSLATED'] = $documentRootShort.$pathInfo; if (substr($shortScriptName,-1) == '/'){ if (!empty($pathInfo) && substr($pathInfo,0,1) == '/'){ $_SERVER['DOCUMENT_URI'] = $shortScriptName.substr($pathInfo,1); } else { $_SERVER['DOCUMENT_URI'] = $shortScriptName.$pathInfo; } } else if (empty($pathInfo) || substr($pathInfo,0,1) == '/'){ $_SERVER['DOCUMENT_URI'] = $shortScriptName.$pathInfo; } else { $_SERVER['DOCUMENT_URI'] = $shortScriptName.'/'.$pathInfo; } $_SERVER['REQUEST_URI'] = $_SERVER['DOCUMENT_URI'].$queryStringWithoutHash; $_SERVER['DOCUMENT_ROOT'] = $documentRootShort; $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // forced $_SERVER['REMOTE_PORT'] = '80'; // forced $_SERVER['SERVER_ADDR'] = '127.0.0.1'; // forced $_SERVER['SERVER_PORT'] = '80'; // forced $_SERVER['SERVER_NAME'] = 'localhost'; // forced $_SERVER['HTTPS'] = null; // forced $_SERVER['REQUEST_TIME'] = time(); } } /** * save previous $_SERVER in $GLOBALS if existing */ public function saveSERVER() { if (!isset($GLOBALS['savedSERVER'])){ $GLOBALS['savedSERVER'] = [ 'saved' => false, 'value' => null ]; } if (!$GLOBALS['savedSERVER']['saved']){ if (!isset($_SERVER)){ $GLOBALS['savedSERVER']['value'] = null; $GLOBALS['savedSERVER']['saved'] = true; } else { $GLOBALS['savedSERVER']['value'] = $_SERVER; $GLOBALS['savedSERVER']['saved'] = true; } } } /** * revert previous $_SERVER in $GLOBALS if existing */ public function revertSERVER() { if (isset($GLOBALS['savedSERVER']['saved']) && $GLOBALS['savedSERVER']['saved']){ if (is_null($GLOBALS['savedSERVER']['value'])){ unset($_SERVER); } else { $_SERVER = $GLOBALS['savedSERVER']['value']; } $GLOBALS['savedSERVER']['saved'] = false; $GLOBALS['savedSERVER']['value'] = null; } } }