1

OK i have this crazy idea, since php does not play nice with G-WAN, maybe the solution is to use phalanger to compile php code to c# mono assembly and then use it from g-wan?

Anyone has any experience with this combination and could help?

OR maybe i'm wrong and G-wan can run php?

Programista
  • 1,037
  • 5
  • 15
  • 38
  • That's a good idea. I will give it a try when the new version is released. (The current version doesn't have C# mono support) – Richard Heath Oct 10 '12 at 20:26
  • So anyone or someone know how to run php directly, g-wan site lacks documentation? – Programista Oct 11 '12 at 08:34
  • On Oct. 21, a crude but unxepectedly efficient PHP scripts interface has been successfully tested and added to G-WAN, see: http://gwan.com/blog/20121021.html#hello.php Here, PHP scripts are run like Java and C scripts, without any handler or configuration. – Gil Oct 22 '12 at 07:26
  • Nice, but no samples again, no code, i just need plain, simple, and full example, ready to run, without trying to figure it out. – Programista Oct 24 '12 at 22:15
  • Wait for v3.10+, it will come with examples. You will just have to copy the PHP script in the /csp folder, like for any other supported language (15 with G-WAN v3.10+) and send a request like: GET /?hello.php (you can also replace the ? by another character and ditch the *.php if you define PHP as the default language). – Gil Oct 29 '12 at 16:29

2 Answers2

2

Did someone tried PH7 ?

PH7 is a PHP engine which allow the host application to compile and execute PHP scripts in-process.

As an embedded interpreter, it allows multiple interpreter states to coexist in the same program, without any interference between them.

PH7 is threadsafe.

But in order to be thread-safe, PH7 must be compiled with the PH7_ENABLE_THREADS compile time directive defined.

Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
1

Well, I did contact the people behind Phalanger (and a few other solutions) to add support for PHP. And their reply (at the time) was that Phalanger was no longer developed.

Now it has been re-emplemented as a CLR language this might give PHP a second life. While I have used the G-WAN 3.9 beta I did not yet try to play with the various languages supported by the Mono runtime.

Regarding the genuine PHP library, I wrote the code below to make it run:

// ----------------------------------------------------------------------------
// php.c: G-WAN using PHP scripts
//
// To build PHP5:
//
//    CFLAGS="-O3" ./configure --enable-embed --enable-maintainer-zts --with-tsrm-pthreads --without-pear
//    make clean
//    make
//    sudo make install
/*    Installing PHP SAPI module:       embed
      Installing PHP CLI binary:        /usr/local/bin/
      Installing PHP CLI man page:      /usr/local/php/man/man1/
      Installing PHP CGI binary:        /usr/local/bin/
      Installing build environment:     /usr/local/lib/php/build/
      Installing header files:          /usr/local/include/php/
      Installing helper programs:       /usr/local/bin/
        program: phpize
        program: php-config
      Installing man pages:             /usr/local/php/man/man1/
        page: phpize.1
        page: php-config.1
      Installing PEAR environment:      /usr/local/lib/php/
      [PEAR] Archive_Tar    - already installed: 1.3.7
      [PEAR] Console_Getopt - already installed: 1.3.0
      [PEAR] Structures_Graph- already installed: 1.0.4
      [PEAR] XML_Util       - already installed: 1.2.1
      [PEAR] PEAR           - already installed: 1.9.4
      Wrote PEAR system config file at: /usr/local/etc/pear.conf
      You may want to add: /usr/local/lib/php to your php.ini include_path
      /home/pierre/Downloads/PHP/php5.4-20/build/shtool install -c ext/phar/phar.phar /usr/local/bin
      ln -s -f /usr/local/bin/phar.phar /usr/local/bin/phar
      Installing PDO headers:          /usr/local/include/php/ext/pdo/       */
/*      
      enabling the 'thread safety' --enable-maintainer-zts option results in:

          error: 'tsrm_ls' undeclared (first use in this function)
*/     
/*
tsrm_ls
    TSRM local storage - This is the actual variable name being passed around 
    inside the TSRMLS_* macros when ZTS is enabled. It acts as a pointer to 
    the start of that thread's independent data storage block.

TSRM
    Thread Safe Resource Manager - This is an oft overlooked, and seldom if 
    ever discussed layer hiding in the /TSRM directory of the PHP source code.
    By default, the TSRM layer is only enabled when compiling a SAPI which 
    requires it (e.g. apache2-worker). All Win32 builds have this layer 
    enabled enabled regardless of SAPI choice.

ZTS
    Zend Thread Ssafety - Often used synonymously with the term TSRM. 
    Specifically, ZTS is the term used by ./configure 
    ( --enable-experimental-zts for PHP4, --enable-maintainer-zts for PHP5), 
    and the name of the #define'd preprocessor token used inside the engine 
    to determine if the TSRM layer is being used.    

TSRMLS_??
    A quartet of macros designed to make the differences between ZTS and 
    non-ZTS mode as painless as possible. When ZTS is not enabled, all 
    four of these macros evaluate to nothing. When ZTS is enabled however,
    they expand out to the following definitions:

        TSRMLS_C tsrm_ls
        TSRMLS_D void ***tsrm_ls
        TSRMLS_CC , tsrm_ls
        TSRMLS_DC , void ***tsrm_ls    


   PHP relies on global variables from resource type identifiers, to 
   function callback pointers, to request specific information such as 
   the symbol tables used to store userspace variables. Attempting to 
   pass these values around in the parameter stack would be more than 
   unruly, it'd be impossible for an application like PHP where it's 
   often necessary to register callbacks with external libraries which
   don't support context data.

   So common information, like the execution stack, the function and 
   class tables, and extension registries all sit up in the global 
   scope where they can be picked up and used at any point in the 
   application.    

   For single-threaded SAPIs like CLI, Apache1, or even Apache2-prefork,
   this is perfectly fine. Request specific structures are initialized 
   during the RINIT/Activation phase, and reset back to their original 
   values during the RSHUTDOWN/Deactivation phase in preparation for 
   the next request. A given webserver like Apache1 can serve up multiple
   pages at once because it spawns multiple processes each in their own 
   process space with their own independant copies of global data.    

   The trouble starts with threaded webservers like Apache2-worker, or IIS
   where two or more threads trying to run the a request at the same time.
   Each thread wants to use the global scope to store its request-specific
   information, and tries to do so by writing to the same 
   storage space. At the least, this would result in userspace variables 
   declared in one script showing up in another. In practice, it leads to 
   quick and disasterous segfaults and completely unpredictable behavior as 
   memory is double freed or written with conflicting information by separate
   threads.        

*/
#pragma include "/usr/local/include/php"
#pragma include "/usr/local/include/php/main"
#pragma include "/usr/local/include/php/TSRM"
#pragma include "/usr/local/include/php/Zend"
#pragma link "/usr/local/lib/libphp5.so"

#include "gwan.h" // G-WAN exported functions

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/syscall.h>

#include <php/sapi/embed/php_embed.h>
#include <php/Zend/zend_stream.h>

static pid_t gettid(void) { return syscall(__NR_gettid); }

// PHP
static int ub_write(const char *str, unsigned int str_len TSRMLS_DC)
{
   puts(str); // this is the stdout output of a PHP script
   return 0;
}

static void log_message(char * message)
{
   printf("log_message: %s\n", message);
}

static void sapi_error(int type, const char * fmt, ...) { }

static void php_set_var(char *varname, char *varval)
{
   zval *var;
   MAKE_STD_ZVAL(var);
   ZVAL_STRING(var, varval, 1);
   zend_hash_update(&EG(symbol_table), varname, strlen(varname) + 1,
                    &var, sizeof(zval*), NULL);
}

static char *php_get_var(char *varname)
{
   zval **data = NULL;
   char *ret = NULL;
   if(zend_hash_find(&EG(symbol_table), varname, strlen(varname) + 1,
                    (void**)&data) == FAILURE)
   {
      printf("Name not found in $GLOBALS\n");
      return "";
   }

   if(!data)
   {
      printf("Value is NULL (not possible for symbol_table?)\n");
      return "";
   }

   ret = Z_STRVAL_PP(data);
   return ret;
}

static int php_init(void)
{
   static int once = 0;
   if(once) return 0;

   once = 1;
   static char *myargv[2] = {"toto.php", NULL};
   php_embed_module.log_message = log_message;
   php_embed_module.sapi_error  = sapi_error;
   php_embed_module.ub_write    = ub_write;
   if(php_embed_init(1, myargv PTSRMLS_CC) == FAILURE)
   {
      printf("php_embed_init error\n");
      return 1;
   }
   return 0;
}

static void php_shutdown()
{
   php_embed_shutdown(TSRMLS_C);
}

static int php_exec(char *str)
{
   zval ret_value;
   int exit_status;
   zend_first_try
   {
      PG(during_request_startup) = 0;

      // run the specified PHP script file
      // sprintf(str, "include (\"% s \ ");", scriptname);

      zend_eval_string(str, &ret_value, "toto.php" TSRMLS_CC);

      exit_status = Z_LVAL(ret_value);
   } zend_catch
   {
      exit_status = EG(exit_status);
   }
   zend_end_try();
   return exit_status;
}

__thread char reply_num[8] = {0};
__thread pid_t tid = 0;

int main(int argc, char *argv[])
{
   if(!tid)
   {
      tid = gettid();
      s_snprintf(reply_num, 8, "%u", tid);
      php_init();
   }

   xbuf_t *reply = get_reply(argv);
   //php_set_var("argv", argv[0]);
   php_set_var(reply_num, "");

   char fmt[] = //"print(\"from php [$test]\n\");\n"
                "$reply%s = \"Hello World (PHP)\";\n";
   char php[sizeof(fmt) + sizeof(reply_num) + 2];
   s_snprintf(php, sizeof(php), fmt, reply_num);

   php_exec(php);

   xbuf_cat(reply, php_get_var(reply_num));
   return 200;
}

If anybody can make this code work with more than one worker thread without crashing the PHP runtime, then PHP will be added to G-WAN.

Here is what G-WAN produces with one single worker thread:

-----------------------------------------------------
weighttp -n 100000 -c 100 -t 1 -k "http://127.0.0.1:8080/?php.c"

finished in 0 sec, 592 millisec, **168744 req/s**, 48283 kbyte/s
requests: 100000 total/started/done/succeeded, 0 failed/errored
status codes: 100000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 29299985 bytes total, 27599985 bytes http, 
         1700000 bytes data
-----------------------------------------------------

That would be great to resolve this PHP threading issue. Thanks for helping anyone!

Gil
  • 3,279
  • 1
  • 15
  • 25
  • I've set it as answer, due to the lack of better solution, g-wan should really have it's own forum. How you get the g-wan 3.9 beta Gil? Are you working at g-wan? Then please tell Pierre that there is a strong need for more code samples and examples for g-wan. – Programista Oct 12 '12 at 16:51
  • G-WAN had a forum hosted by Paco, a G-WAN user, but he scrapped it recently. Stackoverflow is a decent alternative. I am part of the G-WAN development team, but Corporate Registered Users also get access to betas. For the 'more examples' request (there's already 60 of them available), try to be more specific: tell what you would want G-WAN to show how to do. There's a contact form on the G-WAN site for that purpose. – Gil Oct 14 '12 at 10:02
  • Gil, previously, part of the subscription for G-WAN, was access to a "members only" forum. Is this still part of the plan? – Tango Bravo Oct 22 '12 at 03:18
  • After the 'production' release, yes. But that forum will be readable for all - only registered users will be able to post (merely to avoid the tons of crap posted by myriads of anonymous user accounts on the old forum). – Gil Oct 22 '12 at 07:24
  • Someone can post an example how to run PHP more easily, there are new blog entry about this http://gwan.com/blog/20121021.html but it again without any code. Here is something http://gwan.com/faq#languages but still for me it is not to much, help someone, please... – Programista Oct 24 '12 at 10:07