title: Basic RESTful API example using PHP
body: <p>I'm working on getting a basic RESTful API example.  Currently I'm using the example I found <a href="http://coreymaynard.com/blog/creating-a-restful-api-with-php/" rel="nofollow">here</a> however it has some bugs and is incomplete.  </p>
  
  <p>I've already added the following lines to my .htaccess as the example stated.</p>
  
  <pre><code>&lt;IfModule mod_rewrite.c&gt;
      RewriteEngine On
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteCond %{REQUEST_FILENAME} !-d
      RewriteRule api/v1/(.*)$ api/v1/MyAPI.php?request=$1 [QSA,NC,L]
  &lt;/IfModule&gt;
  </code></pre>
  
  <p>My problem however is simply getting the concrete class of mine to print "12".  I don't know which URL to visit to get the message "12" to be shown on the screen.</p>
  
  <p>Here is my abstract class code:</p>
  
  <pre><code>&lt;?php
  abstract class API 
  {
      /** 
       * Property: method
       * The HTTP method this request was made in, either GET, POST, PUT or DELETE
       */
      protected $method = ''; 
      /** 
       * Property: endpoint
       * The Model requested in the URI. eg: /files
       */
      protected $endpoint = ''; 
      /** 
       * Property: verb
       * An optional additional descriptor about the endpoint, used for things that can
       * not be handled by the basic methods. eg: /files/process
       */
      protected $verb = ''; 
      /** 
       * Property: args
       * Any additional URI components after the endpoint and verb have been removed, in our
       * case, an integer ID for the resource. eg: /&lt;endpoint&gt;/&lt;verb&gt;/&lt;arg0&gt;/&lt;arg1&gt;
       * or /&lt;endpoint&gt;/&lt;arg0&gt;
       */
      protected $args = Array();
      /** 
       * Property: file
       * Stores the input of the PUT request
       */
       protected $file = Null;
  
      /** 
       * Constructor: __construct
       * Allow for CORS, assemble and pre-process the data
       */
      public function __construct($request) {
          header("Access-Control-Allow-Orgin: *"); //any origin can be processed by this page
          header("Access-Control-Allow-Methods: *"); //any HTTP method can be accepted
          header("Content-Type: application/json");
  
          $this-&gt;args = explode('/', rtrim($request, '/'));
          $this-&gt;endpoint = array_shift($this-&gt;args);
          if (array_key_exists(0, $this-&gt;args) &amp;&amp; !is_numeric($this-&gt;args[0])) {
              $this-&gt;verb = array_shift($this-&gt;args);
          }
  
          $this-&gt;method = $_SERVER['REQUEST_METHOD'];
          if ($this-&gt;method == 'POST' &amp;&amp; array_key_exists('HTTP_X_HTTP_METHOD', $_SERVER)) {
              if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'DELETE') {
                  $this-&gt;method = 'DELETE';
              } else if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'PUT') {
                  $this-&gt;method = 'PUT';
              } else {
                  throw new Exception("Unexpected Header");
              }
          }
  
          switch($this-&gt;method) {
          case 'DELETE':
          case 'POST':
              $this-&gt;request = $this-&gt;_cleanInputs($_POST);
              break;
          case 'GET':
              $this-&gt;request = $this-&gt;_cleanInputs($_GET);
              break;
          case 'PUT':
              $this-&gt;request = $this-&gt;_cleanInputs($_GET);
              $this-&gt;file = file_get_contents("php://input");
              break;
          default:
              $this-&gt;_response('Invalid Method', 405);
              break;
          }
      }
  
      /**
       * Determine if the concrete class implements a method for the endpoint that the client requested. If it does, then it calls that method, otherwise a 404 
       * response is returned
       */
      public function processAPI() {
          if ((int)method_exists($this-&gt;endpoint) &gt; 0) {
              return $this-&gt;_response($this-&gt;{$this-&gt;endpoint}($this-&gt;args));
          }
          return $this-&gt;_response('', 400);
      }
  
      private function _response($data, $status = 200) {
          header("HTTP/1.1 " . $status . " " . $this-&gt;_requestStatus($status));
          return json_encode($data);
      }
  
      private function _cleanInputs($data) {
          $clean_input = Array();
          if (is_array($data)) {
              foreach ($data as $k =&gt; $v) {
                  $clean_input[$k] = $this-&gt;_cleanInputs($v);
              }
          } else {
              $clean_input = trim(strip_tags($data));
          }
          return $clean_input;
      }
  
      private function _requestStatus($code) {
          $status = array(
              100 =&gt; 'Continue',
              101 =&gt; 'Switching Protocols',
              200 =&gt; 'OK',
              201 =&gt; 'Created',
              202 =&gt; 'Accepted',
              203 =&gt; 'Non-Authoritative Information',
              204 =&gt; 'No Content',
              205 =&gt; 'Reset Content',
              206 =&gt; 'Partial Content',
              300 =&gt; 'Multiple Choices',
              301 =&gt; 'Moved Permanently',
              302 =&gt; 'Found',
              303 =&gt; 'See Other',
              304 =&gt; 'Not Modified',
              305 =&gt; 'Use Proxy',
              306 =&gt; '(Unused)',
              307 =&gt; 'Temporary Redirect',
              400 =&gt; 'Bad Request',
              401 =&gt; 'Unauthorized',
              402 =&gt; 'Payment Required',
              403 =&gt; 'Forbidden',
              404 =&gt; 'Not Found',
              405 =&gt; 'Method Not Allowed',
              406 =&gt; 'Not Acceptable',
              407 =&gt; 'Proxy Authentication Required',
              408 =&gt; 'Request Timeout',
              409 =&gt; 'Conflict',
              410 =&gt; 'Gone',
              411 =&gt; 'Length Required',
              412 =&gt; 'Precondition Failed',
              413 =&gt; 'Request Entity Too Large',
              414 =&gt; 'Request-URI Too Long',
              415 =&gt; 'Unsupported Media Type',
              416 =&gt; 'Requested Range Not Satisfiable',
              417 =&gt; 'Expectation Failed',
              500 =&gt; 'Internal Server Error',
              501 =&gt; 'Not Implemented',
              502 =&gt; 'Bad Gateway',
              503 =&gt; 'Service Unavailable',
              504 =&gt; 'Gateway Timeout',
              505 =&gt; 'HTTP Version Not Supported');
          return ($status[$code])?$status[$code]:$status[500];
      }
  }
  </code></pre>
  
  <p>And here is my concrete class code (trouble on line 8):</p>
  
  <pre><code>&lt;?php
  require_once 'API.php';
  class MyAPI extends API 
  {
      protected $User;
  
      public function __construct($request, $origin)
      {
          echo "12";
          parent::__construct($request);
  
          // Abstracted out for example
          //$APIKey = new Models\APIKey();
          //$User = new Models\User();
  
          if (!array_key_exists('apiKey', $this-&gt;request)) {
              throw new Exception('No API Key provided');
          } else if (!$APIKey-&gt;verifyKey($this-&gt;request['apiKey'], $origin)) {
              throw new Exception('Invalid API Key');
          } else if (array_key_exists('token', $this-&gt;request) &amp;&amp; !$User-&gt;get('token', $this-&gt;request['token'])){
              throw new Exception('Invalid User Token');
          }
  
          //$this-&gt;User = $User;
      }   
  
      /** 
       * Example of an Endpoint
       */
      protected function example()
      {
          if ($this-&gt;method == 'GET') {
              return "Your name is " . $this-&gt;User-&gt;name;
          } else {
              return "Only accepts GET requests";
          }
      }   
  }
  </code></pre>
  
  <p>As you can see line 8 on the concrete class (in the constructor) never gets printed.  Currently I'm trying to make my example work by going to:</p>
  
  <pre><code>www.mysite.com/api/myAPI.php?request=get
  </code></pre>