Skip to content

Commit 4557b9f

Browse files
committed
Merge pull request #26 from tamagokun/nocode_is_faster
Nocode is faster (cleanup and improvements)
2 parents 2d95d4a + d8ab03a commit 4557b9f

15 files changed

+260
-153
lines changed

README.md

+28-33
Original file line numberDiff line numberDiff line change
@@ -19,43 +19,32 @@ $ open http://localhost:9393
1919

2020
![](https://raw.github.com/tamagokun/rackem/master/hello-world.png)
2121

22-
## Getting Started
23-
24-
Rack'em likes [Composer](http://getcomposer.org/), go ahead and install it if it isn't already.
22+
## Features
2523

26-
I like to install Rack'em globally so that I can use it in any project. Unfortunately, Composer does not have a way of doing this by default, so here is an easy way to allow global package installation:
24+
* Tiny
25+
* Provides a common interface for applications
26+
* Environment values are consistent regardless of web server
27+
* Run applications locally without other dependencies
2728

28-
### Setting up Composer for global installtion
29+
## Getting Started
2930

30-
```bash
31-
$ curl https://raw.github.com/gist/4242494/5d6344d2976e07d051ace18d41fa035113353e90/global_composer.sh | sh
32-
```
31+
Rack'em likes [Composer](http://getcomposer.org/), go ahead and install it if it isn't already.
3332

3433
### Installing Rack'em
3534

36-
If you are using the global installtion method from above, you can easily do:
35+
Installing with Composer is the way to go:
3736

3837
```bash
39-
$ cd ~/.composer && composer require rackem/rackem:*
40-
```
41-
42-
Otherwise, you need to add `rackem/rackem` to your project's composer.json:
43-
44-
```json
45-
{
46-
"require": {
47-
"rackem/rackem": "*"
48-
}
49-
}
38+
$ composer require rackem/rackem:@stable
5039
```
5140

52-
There's also a shortcut to do this with Composer:
41+
Installing globally is awesome:
5342

5443
```bash
55-
$ composer require rackem/rackem:*
44+
$ composer global require rackem/rackem:@stable
5645
```
5746

58-
Optionally, there is a PSR autoloader you can use:
47+
Optionally, download Rack'em and require rackem.php:
5948

6049
```php
6150
<?php
@@ -64,7 +53,7 @@ require 'rackem/rackem.php';
6453

6554
## rackem
6655

67-
rackem is a tool for running Rack'em applications without the need for a web server. This makes developing Rack applications with PHP a breeze.
56+
rackem is a HTTP server for running Rack'em applications. This makes developing PHP applications a breeze.
6857

6958
Provide rackem your main application script, and you are good to go:
7059

@@ -77,9 +66,9 @@ $ rackem config.php
7766

7867
## Usage
7968

80-
Any object that has a callable method `call()` can be considered a Rack application. Rack expects call to return an HTTP response array containing: status code, headers, and body.
69+
Anything that `is_callable()` or has an instance method `call()` can be considered an application. The application must return an HTTP response array containing: status code, headers, and body.
8170

82-
Here is an example of a basic Rackem application:
71+
Here is an example of a basic Rack'em application:
8372

8473
```php
8574
<?php
@@ -95,7 +84,7 @@ class App
9584
return \Rackem::run("App");
9685
```
9786

98-
`Rack::run()` accepts 1 of 3 things:
87+
`Rackem::run()` accepts 1 of 3 things:
9988

10089
- String referencing a Class
10190
- Class instance
@@ -113,18 +102,23 @@ return \Rackem::run($app);
113102

114103
## Middleware
115104

116-
Just like Rack, Rack'em supports the use of Middleware. Middleware is basically a Rack application that must be passed `$app` in its constructor, with an optional `$options` parameter. `$app` is an instance of the previous application in the Rack stack.
105+
Fill your rack with middleware for ultimate awesomeness.
106+
107+
Middleware is basically an application that is passed the previous application in the stack and optionally an array of options in its constructor.
117108

118-
Here is an example of a Middleware class that just passes the response on:
109+
The most basic middleware (hint: it doesn't do anything):
119110

120111
```php
121112
<?php
122113

123114
class MyMiddleware
124115
{
125-
public function __construct($app)
116+
public $app, $options;
117+
118+
public function __construct($app, $options = array())
126119
{
127120
$this->app = $app;
121+
$this->options = $options;
128122
}
129123

130124
public function call($env)
@@ -137,7 +131,7 @@ class MyMiddleware
137131
return \Rackem::run( new App() );
138132
```
139133

140-
There is also a Middleware helper class to make things a bit easier:
134+
There is also of course a helper class to make things a bit easier:
141135

142136
```php
143137
<?php
@@ -146,7 +140,8 @@ class MyMiddleware extends \Rackem\Middleware
146140
{
147141
public function call($env)
148142
{
149-
return $this->app->call($env);
143+
// do stuff
144+
return parent::call($env);
150145
}
151146
}
152147
```
@@ -180,7 +175,7 @@ class JsonFormatter extends \Rackem\Middleware
180175
$res = new \Rackem\Response($this->app->call($env));
181176

182177
if($req->params()->format == 'json') //?format=json
183-
$res->write(json_encode($res->body));
178+
$res[] = json_encode($res->body);
184179
return $res->finish();
185180
}
186181
}

bin/rackem

+11-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ if(function_exists("date_default_timezone_set"))
1717
$argv = $GLOBALS['argv'];
1818
array_shift($argv);
1919

20-
$flags = array('h','process');
20+
$flags = array('h','process','ruby','basic');
2121
$args = array();
2222
$opts = array();
2323
while(list($k,$arg) = each($argv))
@@ -41,20 +41,23 @@ while(list($k,$arg) = each($argv))
4141
each($argv);
4242
}
4343

44-
$config = count($args) > 0? $args[0] : 'config.php';
45-
if(!file_exists($config))
44+
$app = count($args) > 0? $args[0] : 'config.php';
45+
46+
if(isset($opts['basic']))
47+
{
48+
$app = "\\Rackem\\BasicWebServer";
49+
}else if(!file_exists($app))
4650
{
47-
echo "configuration {$config} not found\n";
51+
echo "configuration {$app} not found\n";
4852
exit(1);
4953
}
5054

5155
$host = isset($opts['host'])? $opts['host'] : '0.0.0.0';
5256
$port = isset($opts['port'])? $opts['port'] : '9393';
5357
$client = isset($opts['client'])? $opts['client'] : false;
5458

55-
\Rackem::$handler = "php";
56-
$server = new \Rackem\Server($host,$port);
59+
$server = new \Rackem\Server($host, $port, $app);
5760
if(isset($opts['process']) && $opts['process'])
58-
echo $server->process(realpath($config), stream_get_contents(fopen("php://stdin","r")), $client);
61+
echo $server->process(stream_get_contents(fopen("php://stdin","r")), $client);
5962
else
60-
$server->start(realpath($config));
63+
$server->start();

lib/Rackem.php

+8-85
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,9 @@
22

33
class Rackem
44
{
5-
public static $handler = "cgi";
5+
public static $handler = null;
66
protected static $builder = null;
77

8-
public static function cli_req_is_file()
9-
{
10-
return file_exists($_SERVER['SCRIPT_FILENAME']) && !preg_match('/\.php/',$_SERVER['SCRIPT_FILENAME']);
11-
}
12-
138
public static function map($path, $app)
149
{
1510
self::ensure_builder();
@@ -18,103 +13,31 @@ public static function map($path, $app)
1813

1914
public static function run($app = null)
2015
{
21-
if(php_sapi_name() == 'cli-server' && static::cli_req_is_file()) return false;
16+
if(!$app) return false;
2217

2318
self::ensure_builder();
24-
if($app) self::$builder->run($app);
19+
self::$builder->run($app);
2520

26-
if(self::$handler == "php") return self::$builder;
21+
if(!self::$handler) self::$handler = new \Rackem\Handler\Sapi();
22+
if(isset($GLOBALS['argv']) && in_array('--ruby', $GLOBALS['argv'])) self::$handler = new \Rackem\Handler\Ruby();
2723

28-
// typical web server
29-
if(isset($GLOBALS['argv']))
30-
if(in_array('--ruby', $GLOBALS['argv'])) self::$handler = "ruby";
31-
$env = static::env();
32-
ob_start();
33-
$result = self::$builder->call($env);
34-
$output = ob_get_clean();
35-
if($output) $result[1]['X-Output'] = json_encode($output);
36-
static::execute($result, $env);
24+
return self::$handler->run(self::$builder);
3725
}
3826

39-
public static function use_middleware($middleware,$options = array())
27+
public static function use_middleware($middleware, $options = array())
4028
{
4129
self::ensure_builder();
4230
self::$builder->use_middleware($middleware, $options);
4331
}
4432

4533
public static function version()
4634
{
47-
return array(1,1);
35+
return array(0,4,5);
4836
}
4937

5038
/* private */
51-
52-
protected static function env()
53-
{
54-
return self::$handler == "ruby" ? static::build_env_ruby() : static::build_env_cgi();
55-
}
56-
57-
protected static function build_env_cgi()
58-
{
59-
list($request_uri,$script_name) = static::url_parts();
60-
$env = array_merge($_SERVER, array(
61-
"REQUEST_METHOD" => $_SERVER['REQUEST_METHOD'],
62-
"SCRIPT_NAME" => $script_name,
63-
"PATH_INFO" => str_replace($script_name,"",$request_uri),
64-
"SERVER_NAME" => $_SERVER['SERVER_NAME'],
65-
"SERVER_PORT" => $_SERVER['SERVER_PORT'],
66-
"QUERY_STRING" => isset($_SERVER['QUERY_STRING'])? $_SERVER['QUERY_STRING'] : '',
67-
"rack.version" => static::version(),
68-
"rack.url_scheme" => (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'])? 'https' : 'http',
69-
"rack.input" => fopen('php://input', 'r'),
70-
"rack.errors" => fopen('php://stderr', 'wb'),
71-
"rack.multithread" => false,
72-
"rack.multiprocess" => false,
73-
"rack.run_once" => false,
74-
"rack.session" => array(),
75-
"rack.logger" => ""
76-
));
77-
return new \ArrayObject($env);
78-
}
79-
80-
protected static function build_env_ruby()
81-
{
82-
$env = json_decode(file_get_contents('php://stdin'), true);
83-
return new \ArrayObject($env);
84-
}
85-
8639
protected static function ensure_builder()
8740
{
8841
if(!self::$builder) self::$builder = new Rackem\Builder();
8942
}
90-
91-
protected static function execute($result, $env)
92-
{
93-
list($status, $headers, $body) = $result;
94-
if(self::$handler == "ruby")
95-
{
96-
foreach($headers as $k=>&$v) if(is_numeric($v)) $v = (string)$v;
97-
$headers = json_encode($headers);
98-
$body = implode("",$body);
99-
exit(implode("\n",array($status,$headers,$body)));
100-
}
101-
fclose($env['rack.input']);
102-
fclose($env['rack.errors']);
103-
if($env['rack.logger']) $env['rack.logger']->close();
104-
$headers['X-Powered-By'] = "Rack'em ".implode(".",$env['rack.version']);
105-
$headers['Status'] = $status;
106-
header($env['SERVER_PROTOCOL']." ".$status);
107-
foreach($headers as $key=>$values)
108-
foreach(explode("\n",$values) as $value) header("$key: $value");
109-
echo implode("",$body);
110-
exit();
111-
}
112-
113-
protected static function url_parts()
114-
{
115-
$request_uri = ($q = strpos($_SERVER['REQUEST_URI'],'?')) !== false? substr($_SERVER['REQUEST_URI'],0,$q) : $_SERVER['REQUEST_URI'];
116-
$script_name = php_sapi_name() == 'cli-server'? '/' : $_SERVER['SCRIPT_NAME'];
117-
if(strpos($request_uri, $script_name) !== 0) $script_name = dirname($script_name);
118-
return array($request_uri,rtrim($script_name,'/'));
119-
}
12043
}

lib/Rackem/Auth/Basic.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public function username()
9797
/* private */
9898
private function authorization_keys()
9999
{
100-
$keys = array('PHP_AUTH_USER','HTTP_AUTHORIZATION','X-HTTP_AUTHORIZATION','X_HTTP_AUTHORIZATION');
100+
$keys = array('PHP_AUTH_USER','HTTP_AUTHORIZATION','X-HTTP_AUTHORIZATION','X_HTTP_AUTHORIZATION');
101101
foreach($keys as $key)
102102
if(isset($this->env[$key])) $this->key = $key;
103103
return $this->key;

lib/Rackem/BasicWebServer.php

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
namespace Rackem;
3+
4+
class BasicWebServer
5+
{
6+
public function call($env)
7+
{
8+
if(substr($env['PATH_INFO'], -1) == '/') $env['PATH_INFO'] .= "index.html";
9+
$file = new \Rackem\File(getcwd());
10+
return $file->call($env);
11+
}
12+
}

lib/Rackem/Builder.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ public function __construct($app = null, $middleware = array())
1414

1515
public function call($env)
1616
{
17-
$this->use = array_reverse($this->use);
17+
$this->use = $this->use ? array_reverse($this->use) : array();
1818
$app = empty($this->map) ? $this->run : $this->generate_map($this->run, $this->map);
1919
try
2020
{
21-
if(!empty($this->use)) foreach($this->use as $middleware) $app = $middleware($app);
21+
foreach($this->use as $middleware) $app = $middleware($app);
2222
return $app->call($env);
2323
}catch(Exception $e)
2424
{

lib/Rackem/Handler/Rackem.php

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
namespace Rackem\Handler;
3+
4+
class Rackem
5+
{
6+
public function run($app)
7+
{
8+
return $app;
9+
}
10+
11+
public function env()
12+
{
13+
return false;
14+
}
15+
}

lib/Rackem/Handler/Ruby.php

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
namespace Rackem\Handler;
3+
4+
class Ruby
5+
{
6+
public function run($app)
7+
{
8+
$env = $this->env();
9+
10+
ob_start();
11+
list($status, $headers, $body) = $app->call($env);
12+
$output = ob_get_clean();
13+
if($output) $headers['X-Output'] = json_encode($output);
14+
15+
foreach($headers as $k=>&$v) if(is_numeric($v)) $v = (string)$v;
16+
$headers = json_encode($headers);
17+
$body = implode("",$body);
18+
exit(implode("\n",array($status,$headers,$body)));
19+
}
20+
21+
public function env()
22+
{
23+
$env = json_decode(file_get_contents('php://stdin'), true);
24+
return new \ArrayObject($env);
25+
}
26+
}

0 commit comments

Comments
 (0)