Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 99afc12aea1e7f352f2412bdbebf7d2da83bc0cc 0 parents
@oyagev authored
3  .gitignore
@@ -0,0 +1,3 @@
+.project
+.settings
+.buildpath
0  README
No changes.
5 example-app/boot.php
@@ -0,0 +1,5 @@
+<?php
+class User{
+
+ public $fname,$lname,$username,$password;
+}
5 example-app/loop.php
@@ -0,0 +1,5 @@
+<?php
+var_dump($_GET,$_POST,$_SERVER);
+$u = new User();
+var_dump($u);
+echo memory_get_usage(true);
33 server/bootstrap.php
@@ -0,0 +1,33 @@
+<?php
+namespace PHAS;
+
+use PHAS\Lib\Server;
+
+use PHAS\Lib\ServerConfig;
+
+
+
+define('PHAS_ABSPATH',__DIR__.'/');
+define('PHAS_CONFIG_PATH',PHAS_ABSPATH.'config/');
+define('PHAS_LIB_PATH',PHAS_ABSPATH.'lib/');
+define('PHAS_VENDOR_PATH',PHAS_ABSPATH.'vendor/');
+
+function autoload($name){
+ $file = false;
+ if (strpos($name, 'PHAS\\Lib\\')===0){
+ $file = PHAS_LIB_PATH . str_replace('PHAS\\Lib\\', '', $name).'.php';
+ }elseif(strpos($name, 'PHAS\\Vendor\\')===0){
+ $file = PHAS_VENDOR_PATH . str_replace('PHAS\\Vendor\\', '', $name).'.php';
+ }
+
+ if ($file && file_exists($file)){
+ require_once $file;
+ }
+}
+spl_autoload_register('PHAS\autoload');
+
+require_once(PHAS_CONFIG_PATH.'server.php');
+$config = new ServerConfig($serverConfig);
+
+
+
9 server/config/server.php
@@ -0,0 +1,9 @@
+<?php
+$serverConfig = array(
+ 'server.gearman.host' => '127.0.0.1',
+
+ 'app.name' => 'App Name',
+ 'app.script.bootstrap' => PHAS_ABSPATH.'../example-app/boot.php',
+ 'app.script.loop' => PHAS_ABSPATH.'../example-app/loop.php',
+
+);
8 server/entrance.php
@@ -0,0 +1,8 @@
+<?php
+
+use PHAS\Lib\Entrance;
+require_once 'bootstrap.php';
+
+$entrance = new Entrance($config);
+echo $entrance->go();
+
27 server/lib/Entrance.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace PHAS\Lib;
+
+class Entrance{
+ protected $config,$client;
+ function __construct(ServerConfig $config){
+ $this->config = $config;
+ $this->client= new \GearmanClient();
+
+ # Add default server (localhost).
+ $this->client->addServer($config->get('server.gearman.host'));
+
+ }
+
+ function go(){
+ $params = json_encode(array(
+ 'post' => $_POST,
+ 'get' => $_GET,
+ 'server' => $_SERVER
+ ));
+
+ return $result = $this->client->do('serve',$params);
+
+ }
+
+}
30 server/lib/Server.php
@@ -0,0 +1,30 @@
+<?php
+namespace PHAS\Lib;
+
+use PHAS\Vendor\Thread;
+
+class Server {
+ protected $config;
+ function __construct(ServerConfig $config){
+ $this->config = $config;
+ $this->startNewWorker();
+ }
+
+ function startNewWorker(){
+ if( ! Thread::available() ) {
+ die( 'Threads not supported' );
+ }
+ $t = new Thread( '\PHAS\Lib\run' );
+ $t->start($this->config);
+
+
+ }
+
+ static function run($config){
+ $worker = new Worker($config);
+ }
+}
+
+function run($config){
+ $worker = new Worker($config);
+}
25 server/lib/ServerConfig.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace PHAS\Lib;
+
+class ServerConfig {
+ public $opts=array();
+
+
+ function __construct($opts){
+ $this->opts = array_merge($this->opts,$opts);
+ }
+
+ function get($key){
+ if (isset($this->opts[$key])){
+ return $this->opts[$key];
+ }
+ throw new Exception('Config not found: '.$key);
+ }
+ function set($key,$value){
+ $this->opts[$key] = $value;
+ return $this;
+ }
+
+
+}
52 server/lib/Worker.php
@@ -0,0 +1,52 @@
+<?php
+namespace PHAS\Lib;
+
+class Worker{
+ protected $config,$worker;
+ function __construct(ServerConfig $config){
+ $this->config = $config;
+ $this->worker = new \GearmanWorker();
+ $this->worker->addServer($config->get('server.gearman.host'));
+ $this->worker->addFunction('serve',array($this,'workApp'));
+ $this->bootApp();
+ }
+
+
+ function bootApp(){
+ $app = $this->config->get('app.script.bootstrap');
+ if (file_exists($app)) require_once $app;
+
+ while (1)
+ {
+
+
+ $ret= $this->worker->work();
+ if ($this->worker->returnCode() != GEARMAN_SUCCESS)
+ break;
+ }
+ }
+
+ function workApp($job){
+
+
+
+ $params = json_decode($job->workload());
+ $_POST = (array)$params->post;
+ $_GET = (array)$params->get;
+ $_SERVER = (array)$params->server;
+ $_REQUEST = array_merge($_GET,$_POST);
+ //$_SERVER['REQUEST_URI'] = '/oht/';
+
+ $app = $this->config->get('app.script.loop');
+ ob_start();
+
+
+ include $app;
+
+ return ob_get_clean();
+ }
+
+
+
+
+}
43 server/loop.php
@@ -0,0 +1,43 @@
+<?php
+# Create our worker object.
+$worker= new GearmanWorker();
+
+# Add default server (localhost).
+$worker->addServer();
+
+# Register function "reverse" with the server.
+$worker->addFunction("reverse", "reverse_fn");
+$worker->addFunction("fire", "fire_in_the_hole");
+
+while (1)
+{
+ print "Waiting for job...\n";
+
+ $ret= $worker->work();
+ if ($worker->returnCode() != GEARMAN_SUCCESS)
+ break;
+}
+
+# A much simple reverse function
+function reverse_fn($job)
+{
+ $workload= $job->workload();
+ echo "Received job: " . $job->handle() . "\n";
+ echo "Workload: $workload\n";
+ $result= strrev($workload);
+ echo "Result: $result\n";
+ return $result;
+}
+
+
+function fire_in_the_hole($job){
+ $params = json_decode($job->workload());
+ $_POST = $params->post;
+ $_GET = $params->get;
+ $_SERVER = $params->server;
+
+ $app = __DIR__.'/../example-app/hello.php';
+ ob_start();
+ include $app;
+ return ob_get_clean();
+}
6 server/server-loop.php
@@ -0,0 +1,6 @@
+<?php
+
+use PHAS\Lib\Server;
+require_once 'bootstrap.php';
+
+new Server($config);
217 server/vendor/Thread.php
@@ -0,0 +1,217 @@
+<?php
+
+namespace PHAS\Vendor;
+
+/**
+ * Implements threading in PHP
+ *
+ * @package <none>
+ * @version 1.0.0 - stable
+ * @author Tudor Barbu <miau@motane.lu>
+ * @copyright MIT
+ */
+class Thread {
+ const FUNCTION_NOT_CALLABLE = 10;
+ const COULD_NOT_FORK = 15;
+
+ /**
+ * possible errors
+ *
+ * @var array
+ */
+ private $errors = array(
+ Thread::FUNCTION_NOT_CALLABLE => 'You must specify a valid function name that can be called from the current scope.',
+ Thread::COULD_NOT_FORK => 'pcntl_fork() returned a status of -1. No new process was created',
+ );
+
+ /**
+ * callback for the function that should
+ * run as a separate thread
+ *
+ * @var callback
+ */
+ protected $runnable;
+
+ /**
+ * holds the current process id
+ *
+ * @var integer
+ */
+ private $pid;
+
+ /**
+ * checks if threading is supported by the current
+ * PHP configuration
+ *
+ * @return boolean
+ */
+ public static function available() {
+ $required_functions = array(
+ 'pcntl_fork',
+ );
+
+ foreach( $required_functions as $function ) {
+ if ( !function_exists( $function ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * class constructor - you can pass
+ * the callback function as an argument
+ *
+ * @param callback $_runnable
+ */
+ public function __construct( $_runnable = null ) {
+ if( $_runnable !== null ) {
+ $this->setRunnable( $_runnable );
+ }
+ }
+
+ /**
+ * sets the callback
+ *
+ * @param callback $_runnable
+ * @return callback
+ */
+ public function setRunnable( $_runnable ) {
+ if( self::runnableOk( $_runnable ) ) {
+ $this->runnable = $_runnable;
+ }
+ else {
+ throw new Exception( $this->getError( Thread::FUNCTION_NOT_CALLABLE ), Thread::FUNCTION_NOT_CALLABLE );
+ }
+ }
+
+ /**
+ * gets the callback
+ *
+ * @return callback
+ */
+ public function getRunnable() {
+ return $this->runnable;
+ }
+
+ /**
+ * checks if the callback is ok (the function/method
+ * actually exists and is runnable from the current
+ * context)
+ *
+ * can be called statically
+ *
+ * @param callback $_runnable
+ * @return boolean
+ */
+ public static function runnableOk( $_runnable ) {
+ return ( function_exists( $_runnable ) && is_callable( $_runnable ) );
+ }
+
+ /**
+ * returns the process id (pid) of the simulated thread
+ *
+ * @return int
+ */
+ public function getPid() {
+ return $this->pid;
+ }
+
+ /**
+ * checks if the child thread is alive
+ *
+ * @return boolean
+ */
+ public function isAlive() {
+ $pid = pcntl_waitpid( $this->pid, $status, WNOHANG );
+ return ( $pid === 0 );
+
+ }
+
+ /**
+ * starts the thread, all the parameters are
+ * passed to the callback function
+ *
+ * @return void
+ */
+ public function start() {
+ $pid = @ pcntl_fork();
+ if( $pid == -1 ) {
+ throw new Exception( $this->getError( Thread::COULD_NOT_FORK ), Thread::COULD_NOT_FORK );
+ }
+ if( $pid ) {
+ // parent
+ $this->pid = $pid;
+ }
+ else {
+ // child
+ pcntl_signal( SIGTERM, array( $this, 'signalHandler' ) );
+ $arguments = func_get_args();
+ if ( !empty( $arguments ) ) {
+ call_user_func_array( $this->runnable, $arguments );
+ }
+ else {
+ call_user_func( $this->runnable );
+ }
+
+ exit( 0 );
+ }
+ }
+
+ /**
+ * attempts to stop the thread
+ * returns true on success and false otherwise
+ *
+ * @param integer $_signal - SIGKILL/SIGTERM
+ * @param boolean $_wait
+ */
+ public function stop( $_signal = SIGKILL, $_wait = false ) {
+ if( $this->isAlive() ) {
+ posix_kill( $this->pid, $_signal );
+ if( $_wait ) {
+ pcntl_waitpid( $this->pid, $status = 0 );
+ }
+ }
+ }
+
+ /**
+ * alias of stop();
+ *
+ * @return boolean
+ */
+ public function kill( $_signal = SIGKILL, $_wait = false ) {
+ return $this->stop( $_signal, $_wait );
+ }
+
+ /**
+ * gets the error's message based on
+ * its id
+ *
+ * @param integer $_code
+ * @return string
+ */
+ public function getError( $_code ) {
+ if ( isset( $this->errors[$_code] ) ) {
+ return $this->errors[$_code];
+ }
+ else {
+ return 'No such error code ' . $_code . '! Quit inventing errors!!!';
+ }
+ }
+
+ /**
+ * signal handler
+ *
+ * @param integer $_signal
+ */
+ protected function signalHandler( $_signal ) {
+ switch( $_signal ) {
+ case SIGTERM:
+ exit( 0 );
+ break;
+ }
+ }
+}
+
+// EOF
Please sign in to comment.
Something went wrong with that request. Please try again.