Router.php
<?php
namespace Tiny;
class Router implements \Tiny\IFace\Router {
protected $dir;
protected $base;
protected $fileMap;
public function __construct($pubDir,$baseUrl='/'){
$this->dir = $pubDir;
$this->base = $baseUrl;
$this->fileMap = $this->fileMap($pubDir);
}
public function filePath($url='/'){
$base = $this->base;
$relativeUrl = $this->relativePath($url);
if (!$relativeUrl)return FALSE;
// var_dump("base:".$this->base);
$fileKey = $this->getFileKey($url);
$action = $this->getAction($url,$fileKey);
$slug = $this->getSlug($url,$fileKey,$action);
$file = $this->getFile($fileKey,$action,$slug);
$path = str_replace(['////','///','//'],'/',$this->dir.'/'.$file);
// var_dump("fkey:".$fileKey);
// var_dump("action:".$action);
if ($file==null
||!is_file($path)){
return false;
}
return $path;
}
public function url($view='',$action='',$slug=''){
$base = $base ?? $this->base;
$url = $this->base.'/'.$view.'/'.$slug.'/'.$action.'/';
$url = $this->cleanPath($url);
return $url;
}
public function isRequested($url){
$path = $this->filePath($url,$this->base);
if ($path===null||$path===false)return false;
return true;
}
public function disablePublic($fileKey,$action='*',$slug='*'){
// return;
if ($action!='*'&&$slug!='*'){
throw new \Exception("Currently only fileKey (first paramater) is accepted on Router->disablePublic(...); \$action & \$slug must be wildcard (*)");
}
$fileKey = $this->cleanPath($fileKey);
// var_dump($fileKey);
if (isset($this->fileMap[$fileKey])){
unset($this->fileMap[$fileKey]);
return;
}
if (substr($fileKey,-2)!='*/'){
throw new \Exception("File Key '{$fileKey}' does not exist or has already been disabled.");
}
$fileKey = $this->cleanPath(substr($fileKey,0,-2));
$matches = array_filter($this->fileMap,
function($key) use ($fileKey){
if (substr($key,0,strlen($fileKey))==$fileKey){
return true;
}
},
ARRAY_FILTER_USE_KEY);
foreach ($matches as $key=>$value){
unset($this->fileMap[$key]);
}
}
protected function relativePath($url){
$url = parse_url($url,PHP_URL_PATH);
$base = $this->base;
$url = $this->cleanPath($url);
if (substr($url,0,strlen($base))!=$base){
return false;
}
$url = substr($url,strlen($base));
if (substr($url,0,1)!='/')$url = '/'.$url;
return $url;
}
public function cleanUrl($url){
return $this->cleanPath($url);
}
protected function cleanPath($url){
$url = str_replace(['////','///','//'],'/','/'.$url);
if (substr($url,-1)==='/'){
$url = substr($url,0,-1);
}
$ext = pathinfo($url,PATHINFO_EXTENSION);
if ($ext==null){
$url .= '/';
}
return $url;
}
protected function getSlug($url,$fileKey,$action){
$url = $this->relativePath($url);
$url = substr($url,strlen($fileKey));
while (substr($url,-1)=='/')$url = substr($url,0,-1);
$actionLength = strlen($action);
if ($actionLength!=0){
$url = substr($url,0,-$actionLength);
}
return $url;
}
protected function getAction($url,$fileKey){
$url = $this->relativePath($url);
$url = substr($url,strlen($fileKey));
if (substr($url,-1)==='/')$url = substr($url,0,-1);
$parts = explode('/',$url);
$actionWord = array_pop($parts);
$views = $this->fileMap;
if (isset($views[$fileKey][$actionWord])){
return $actionWord;
} else {
return '';
}
}
protected function getFileKey($url){
$map = $this->fileMap;
$url = parse_url($url,PHP_URL_PATH);
$url = $this->relativePath($url);
$parts = explode('/',$url);
$fileKey = str_replace('//','/','/'.implode('/',$parts) );
$ext = pathinfo($fileKey,PATHINFO_EXTENSION);
if ($ext==''||$ext==NULL)$fileKey .= '/';
$url = str_replace(['///','//'],'/','/'.$url);
if (isset($map[$url])){
return $url;
}
while(!isset($map[$fileKey])
&&strlen($fileKey)>2){
array_pop($parts);
$fileKey = str_replace('//','/','/'.implode('/',$parts).'/');
}
if (isset($map[$fileKey])){
return $fileKey;
} else {
return null;
}
}
public function getFile($fileKey,$action,$slug){
$file = @$this->fileMap[$fileKey][$action][strlen($slug)>0 ? '--slug--' : '--no_slug--'];
if ($file==null||strlen($file)<=0)return false;
return $file;
}
public function getUrlParts($url = NULL){
$url = $_SERVER['REQUEST_URI'] ?? $url;
$fileKey = $this->getFileKey($url);
$action = $this->getAction($url,$fileKey);
$slug = $this->getSlug($url,$fileKey,$action);
$parts['fileKey'] = $fileKey;
$parts['action'] = $action;
$parts['slug'] = $slug;
return $parts;
}
protected function fileMap(){
$pubDir = $this->dir;
$paths = $this->allChildren($pubDir);
$map = [];
foreach ($paths as $path){
$ext = pathinfo($path,PATHINFO_EXTENSION);
if ($ext=='php'){
$baseName = basename($path);
$fileName = substr($baseName,0,strpos($baseName,'.'));
if ($fileName=='index')$fileName = '';
$fileKey = $this->cleanPath(dirname($path).'/'.$fileName.'/');
$action = $this->parseAction($baseName);
$isSlugString = $this->parseSlug($baseName);
$map[$fileKey][$action][$isSlugString] = $path;
} else {
$map[$this->cleanPath($path)]['']['--no_slug--'] = $path;
}
}
return $map;
}
public function parseSlug($baseName){
$parts = explode('.',$baseName);
$parts = array_reverse($parts);
if (strtolower($parts[0])!=='php'){
return '--no_slug--';
throw new \Exception ("basename {$baseName} does not have a php extension");
}
if (count($parts)===2)return '--no_slug--';
if (count($parts)===3
&&$parts[1]=='item'){
return '--slug--';
}
if (count($parts)>3
&&$parts[2]=='item'){
return '--slug--';
}
return '--no_slug--';
}
public function parseAction($baseName){
$parts = explode('.',$baseName);
$parts = array_reverse($parts);
if (strtolower($parts[0])!=='php'){
return '';
throw new \Exception ("basename {$baseName} does not have a php extension");
}
if (count($parts)==2
||$parts[1]=='item'){
return '';
}
return $parts[1];
}
public function allChildren($dir, $relPath = '/'){
$paths = [];
$handle = opendir($dir);
while ($file=readdir($handle)){
if ($file=='.'||$file=='..')continue;
if (is_dir($dir.'/'.$file)){
$paths = array_merge($paths,$this->allChildren($dir.'/'.$file,$relPath.$file.'/'));
} else {
$paths[] = $relPath.$file;
}
}
return $paths;
}
}
?>