title: Security implications of letting user call php methods
body: <p>What are the risks associated with doing something like this? For instance, there may be some special characters that would pass the validations, allow the user to include unwanted files or make the php functions used here fail or not behave as intended, that I should be aware of.</p>
  <pre><code>//parse the uri
  $uri=trim(parse_url(urldecode($_SERVER['REQUEST_URI']))['path'],'/');
  $path=saferDirnameAndBasename($uri);
  $class=$path-&gt;dir;
  $method=$path-&gt;base;
  
  //or it could be done with url rewritting, or just parameters, like:
  //$class=$_GET['c'];
  //$method=$_GET['m'];
  
  $class=filter_var($class,FILTER_UNSAFE_RAW,FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH);
  $method=filter_var($method,FILTER_UNSAFE_RAW,FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH);
  
  if(preg_match('/[^a-z0-9_\/-]/i',$class)||preg_match('/[^a-z0-9_]/i',$method)) exit;
  
  $file=__DIR__.'/folder-where-public-clases-are/'.$class.'.php'; //note that it's allowing subdirs, but I don't want the user to go up
  if(!file_exists($file)) exit;
  include_once($file);
  
  //remove the dashes too, my-class.php should contain myclass
  $class=str_replace('-','',$class);
  
  $path=saferDirnameAndBasename($class);
  $namespace='\\publicClasses\\'.str_replace('/','\\',$path-&gt;dir); //dir/class -&gt; \publicClasses\dir
  $name=$path-&gt;base;
  $fullname=$namespace.'\\'.$name;
  
  if(!class_exists($fullname)) exit;
  $obj=new $fullname;
  
  if(!method_exists($obj,$method)) exit; //I know this doesn't account for visibility prior to php 7.4
  
  call_user_func([$obj,$method]);
  
  function saferDirnameAndBasename($path) {
      $parts=explode('/',$path);
      return (object)[
          'base'=&gt;array_pop($parts),
          'dir'=&gt;implode('/',$parts)
      ];
  }
  </code></pre>
  <p>A file in <code>folder-where-public-clases-are</code> would cointain</p>
  <pre><code>&lt;?php
      namespace publicClasses;
      class myclass {
          public function test() {
          }
      }
  </code></pre>
  <p>This would make a <em>dynamic</em> router, where the paths shouldn't be defined beforehand. Private code should just live outside the <code>publicClasses</code> namespace.</p>