Skip to content

Instantly share code, notes, and snippets.

@tamagokun
Created June 12, 2013 15:38
Show Gist options
  • Save tamagokun/5766442 to your computer and use it in GitHub Desktop.
Save tamagokun/5766442 to your computer and use it in GitHub Desktop.
Rack'em app for serving Wordpress applications via php-cgi. No longer needing to configure nginx/apache locally ftw.
<?php
require 'vendor/autoload.php';
class Cgi
{
public $app, $public_folder;
public function __construct($app, $public_folder)
{
$this->app = $app;
$this->public_folder = $public_folder;
}
public function call($env)
{
if($this->is_valid($env['PATH_INFO']))
return $this->run($env, realpath($this->public_folder.$env['PATH_INFO']));
else
return $this->app->call($env);
}
public function is_valid($path)
{
$path = realpath($this->public_folder.$path);
if(strpos($path, $this->public_folder) !== false && is_file($path) && is_executable($path)) return true;
return false;
}
//private
protected function run($env, $path)
{
$spec = array(
0 => array("pipe", "rb"),
1 => array("pipe", "wb"),
2 => array("pipe", "wb")
);
$env['DOCUMENT_ROOT'] = $this->public_folder;
foreach($env as $k=>$v) if(is_string($v)) putenv("$k=$v");
$body = str_replace("\0\z","",stream_get_contents($env['rack.input']));
if(($length = strlen($body))) putenv("CONTENT_LENGTH={$length}");
$proc = proc_open($path, $spec, $pipes);
stream_set_blocking($pipes[2], 0);
if(!is_resource($proc)) return array(500, array('Content-Type'=>'text/html'), array('<h1>Internal Server Error</h1>'));
if(isset($body)) fwrite($pipes[0], $body);
$raw = stream_get_contents($pipes[1]);
fclose($pipes[1]);
echo stream_get_contents($pipes[2]);
fclose($pipes[2]);
proc_close($proc);
$headers = array();
$status = 200;
list($raw_header, $body) = preg_split('/\r?\n\r?\n/', $raw, 2);
$raw_header = preg_split('/\r?\n/', $raw_header);
foreach($raw_header as $line)
{
list($key, $value) = preg_split('/\s*\:\s*/', $line, 2);
if(isset($headers[$key]))
$headers[$key] .= "\n$value";
else
$headers[$key] = $value;
}
if(isset($headers['Status']))
{
preg_match('/(\d{3})/', $headers['Status'], $m);
$status = $m[0];
unset($headers['Status']);
}
return array($status, $headers, array($body));
}
}
class Php extends Cgi
{
public $php_exec;
public function __construct($app, $public_folder, $php_exec='php-cgi')
{
parent::__construct($app, $public_folder);
$this->php_exec = $php_exec;
}
public function is_valid($path)
{
list($script, $info) = $this->path_parts($this->public_folder.$path);
if(!preg_match('/\.php$/',$script) && !is_dir($script)) return false;
if(strpos($script, $this->public_folder) === false) return false;
return true;
}
//private
protected function run($env, $path)
{
list($script, $info) = $this->path_parts($path);
if(is_dir($script))
{
$script = rtrim($script,'/').'/index.php';
$env['PATH_INFO'] = rtrim($env['PATH_INFO'],'/').'/';
}
$env['SCRIPT_FILENAME'] = $script;
putenv("REDIRECT_STATUS=0");
return parent::run($env, $this->php_exec);
}
protected function path_parts($path)
{
if(strpos($path, '.php') === false) return array($path, null);
list($script, $info) = explode('.php', $path, 2);
return array($script.'.php', $info);
}
}
class Wordpress extends Php
{
public function call($env)
{
$path = realpath($this->public_folder.$env['PATH_INFO']);
if(!$this->is_valid($env['PATH_INFO']))
{
if(is_file($path))
{
$file = new \Rackem\File($this->public_folder);
return $file->call($env);
}
$path = $this->public_folder.'/index.php'.$env['PATH_INFO'];
}
return $this->run($env, $path);
}
}
return \Rackem::run(new Wordpress(null, __DIR__.'/wordpress'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment