Giter Club home page Giter Club logo

ph7's Introduction

PH7 - An Embedded Implementation of PHP (C Library).

Build Status

PH7 is a in-process software C library which implements a highly-efficient embeddable bytecode compiler and a virtual machine for the PHP programming language. In other words, PH7 is a PHP engine which allow the host application to compile and execute PHP scripts in-process. PH7 is to PHP what SQLite is to SQL.

PH7 implements most of the constructs introduced by the PHP 5.3 release such as heredoc, nowdoc, gotos, classes, anonymous functions, closures and so on and introduces very powerful extensions to the PHP programming language such as:

  • Function & Method Overloading.
  • Full Type Hinting.
  • Introducing comma expressions.
  • Introducing the eq and ne operators for strict string comparison.
  • Improved operators precedences.
  • Powerful OO subsystem.
  • Function arguments can take any complex expressions as their default values.
  • 64-bit integer arithmetic for all platforms.
  • Native UTF-8 support.
  • Written in ANSI C, thread-safe, full-reentrant; compile and run unmodified in any platform including restricted embedded devices with a C compiler.
  • Amalgamation: All C source code for PH7 are combined into a single source file.
  • Built with more 470 function including an XML parser (with namespace support), INI processor, CSV reader/writer, UTF-8 encoder/decoder, zip archive extractor, JSON encoder/decoder, random number/strings generator, native and efficient File IO for Windows and UNIX systems and many more without the need of any external library to link with.
  • PH7 is an Open-Source product.

As an embedded interpreter, it allows multiple interpreter states to coexist in the same program, without any interference between them. Programmatically, foreign functions in C/C++ can be added and values can be defined in the PHP environment. Being a quite small program, it is easy to comprehend, get to grips with, and use.

PH7 History - Why PHP?

PH7 was developed in the early 2011 by a Tunisian startup for a French conglomerate which was looking for a way to power the web interface of their commercial routers. Previously the technology used by the conglomerate was obsolete and based on a minimal HTTP server (micro-httpd written by Jef Poskanzer) and a hard-coded binary (the web interface) served via old CGI interface. This poor combination shows its limitation when the company decided to switch to a user-configurable (self config) routers where everything must be done via the web interface. This involve a dynamic web UI that have to deal with many issues. In order to keep the low level software layer of the router untouched, it was decided to write all the web interface in a dynamic web oriented programming language and the compilation result to be executed by a virtual machine (PH7) and thus leaving the low-level stack of the router untouched.

PH7 in 5 Minutes or Less

Here is what you do to start experimenting with the PH7 engine without having to do a lot of tedious reading and configuration:

Below is a simple C program that demonstrates how to use the C/C++ interface to PH7. This program compile and execute the following PHP script:

<?php
 echo 'Welcome guest'.PHP_EOL;
 echo 'Current system time is: '.date('Y-m-d H:i:s').PHP_EOL;
 echo 'and you are running '.php_uname();
?>

That is, this simple PHP script when running should display a greeting message, the current system time and the host operating system. A typical output of this program would look like this:

 Welcome guest
 Current system time is: 2012-09-14 10:08:44
 and you are running Microsoft Windows 7 localhost 6.1 build 7600 x86

Here is the C code. Note that you can get a working version of this program here:

/* Compile this file together with the ph7 engine source code to generate
* the executable. For example:
* gcc -W -Wall -O6 -o ph7_test ph7_intro.c ph7.c
*/
/*
* This simple program is a quick introduction on how to embed and start
* experimenting with the PH7 engine without having to do a lot of tedious
* reading and configuration.
*
* For an introduction to the PH7 C/C++ interface, please refer to this page
* http://ph7.symisc.net/api_intro.html
* For the full C/C++ API reference guide, please refer to this page
* http://ph7.symisc.net/c_api.html
*/
/*
* The following is the PHP program to execute.
* <?php
* echo 'Welcome guest'.PHP_EOL;
* echo 'Current system time is: '.date('Y-m-d H:i:s').PHP_EOL;
* echo 'and you are running '.php_uname();
* ?>
* That is, this simple program when running should display a greeting
* message, the current system time and the host operating system.
* A typical output of this program would look like this:
*
* Welcome guest
* Current system time is: 2012-09-14 02:08:44
* and you are running Microsoft Windows 7 localhost 6.1 build 7600 x86
*
*/
#define PHP_PROG "<?php "\
"echo 'Welcome guest'.PHP_EOL;"\
"echo 'Current system time is: '.date('Y-m-d H:i:s').PHP_EOL;"\
"echo 'and you are running '.php_uname();"\
"?>"
/* Make sure you have the latest release of the PH7 engine
* from:
* http://ph7.symisc.net/downloads.html
*/
#include <stdio.h>
#include <stdlib.h>
/* Make sure this header file is available.*/
#include "ph7.h"
/*
* Display an error message and exit.
*/
static void Fatal(const char *zMsg)
{
  puts(zMsg);
  /* Shutdown the library */
  ph7_lib_shutdown();
  /* Exit immediately */
   exit(0);
 }
/*
* VM output consumer callback.
* Each time the virtual machine generates some outputs, the following
* function gets called by the underlying virtual machine to consume
* the generated output.
* All this function does is redirecting the VM output to STDOUT.
* This function is registered later via a call to ph7_vm_config()
* with a configuration verb set to: PH7_VM_CONFIG_OUTPUT.
*/
static int Output_Consumer(const void *pOutput, unsigned int nOutputLen, void *pUserData /* Unused */)
{
  /*
   * Note that it's preferable to use the write() system call to display the output
   * rather than using the libc printf() which everybody now is extremely slow.
   */
  printf("%.*s",
      nOutputLen,
      (const char *)pOutput /* Not null terminated */
   );
    /* All done, VM output was redirected to STDOUT */
    return PH7_OK;
 }
/*
* Main program: Compile and execute the PHP program defined above.
*/
int main(void)
{
  ph7 *pEngine; /* PH7 engine */
  ph7_vm *pVm; /* Compiled PHP program */
  int rc;
  /* Allocate a new PH7 engine instance */
  rc = ph7_init(&pEngine);
  if( rc != PH7_OK ){
   /*
    * If the supplied memory subsystem is so sick that we are unable
    * to allocate a tiny chunk of memory, there is no much we can do here.
    */
   Fatal("Error while allocating a new PH7 engine instance");
  }
  /* Compile the PHP test program defined above */
  rc = ph7_compile_v2(
      pEngine, /* PH7 engine */
      PHP_PROG, /* PHP test program */
      -1 /* Compute input length automatically*/,
      &pVm, /* OUT: Compiled PHP program */
      0 /* IN: Compile flags */
   );
  if( rc != PH7_OK ){
    if( rc == PH7_COMPILE_ERR ){
      const char *zErrLog;
      int nLen;
     /* Extract error log */
     ph7_config(pEngine,
       PH7_CONFIG_ERR_LOG,
       &zErrLog,
       &nLen
     );
   if( nLen > 0 ){
     /* zErrLog is null terminated */
     puts(zErrLog);
    }
  }
  /* Exit */
  Fatal("Compile error");
}
/*
 * Now we have our script compiled, it's time to configure our VM.
 * We will install the output consumer callback defined above
 * so that we can consume and redirect the VM output to STDOUT.
 */
rc = ph7_vm_config(pVm,
      PH7_VM_CONFIG_OUTPUT,
      Output_Consumer, /* Output Consumer callback */
      0 /* Callback private data */
   );
  if( rc != PH7_OK ){
     Fatal("Error while installing the VM output consumer callback");
  }
/*
* And finally, execute our program. Note that your output (STDOUT in our case)
* should display the result.
*/
ph7_vm_exec(pVm,0);
/* All done, cleanup the mess left behind.
*/
ph7_vm_release(pVm);
ph7_release(pEngine);
return 0;
}

We create a new PH7 engine instance using a call to ph7_init() on line 86. This is often the first PH7 API call that an application makes and is a prerequisite in order to compile PHP code using one of the compile interfaces.

We compile our PHP test program on line 95 using the ph7_compile_v2() interface.

We configure our Virtual Machine on line 125 by setting a VM output consumer callback named Output_Consumer(). All this callback does is redirecting the VM output to STDOUT using the libc printf() routine or the write() system call.

And finally we execute our PHP program on line 137 using a call to ph7_vm_exec(). You should see now the greeting message, the current date and the host operating system.

Clean-up is done on line 140 and 141 respectively via calls to ph7_vm_release() and ph7_release().

Now, Compile this C file together with the PH7 engine source code to generate the executable. For example:

gcc -W -Wall -O6 -o ph7_test ph7_intro.c ph7.c

When running [./ph7_test ] you should see the greeting message, the current system time and the host operating system.

The PH7 download page includes a simple stand-alone PHP interpreter named ph7 (or ph7.exe on windows) that allows the user to enter and execute PHP files against a PH7 engine. This utility is available in prebuilt binaries forms or can be compiled from source. You can get a copy of the PH7 interpreter from the download page.

To start the ph7 program, just type "ph7" followed by the name of the PHP file to compile and execute. That is, the first argument is to the interpreter, the rest are scripts arguments, press "Enter" and the PHP code will be executed.

If something goes wrong while processing the PHP script due to a compile-time error, your error output (STDOUT) should display the compile-time error messages.

Usage example of the ph7 interpreter:

Running the interpreter

ph7 scripts/hello_world.php

Running the interpreter with script arguments

ph7 scripts/mp3_tag.php /usr/local/path/to/my_mp3s

Useful links to start with

Download : Get a copy of the last public release of the PH7 engine, start embedding and enjoy programming with.

Distinctive Features: This document enumerates and describes some of the features and the powerfull extensions introduced by the PH7 engine.

Frequently Asked Questions: FAQ: The title of the document says all...

Copyright/Licensing: PH7 is dual-licensed and is available free of charge for open source projects. Find more on the licensing situation there.

Online Community Support: Need some help, join the PH7 online community.

PH7 Programming Interfaces

Documentation describing the APIs used to program PH7. Note that PH7 is very easy to learn, even for new programmer. Here is some useful links to start with:

PH7 In 5 Minutes Or Less: Gives a high-level overview on the how to embed the PH7 engine in a host application.

An Introduction To The PH7 C/C++ Interface: Gives an overview and roadmap to the C/C++ interface to PH7.

C/C++ API Reference Guide: This document describes each API function in details.

Foreign Function Implementation: Is a how-to guide on how to install C functions and invoke them from your PHP script.

Constant Expansion Mechanism: Is a how-to guide on how to install foreign constants and expand their values from your PHP script.

ph7's People

Contributors

biserkov avatar red54 avatar symisc avatar timgates42 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ph7's Issues

file_get_contents not work

This is my example PHP code to read http file with file_get_contents but its returns nothing.

<?php

echo file_get_contents("http://www.google.com/robots.txt");

GIthub should have thanks feature

Dude this PH7 is amazing, the memory use is extremely low less than 500bytes serving several forms and with several functions added + loading/saving session data that i have yet to complete. But so far within about 4 days i have added ( with kids annoying me ;) )

{"header", ph7_header}, {"setcookie", ph7_setcookie}, {"memory_get_usage", ph7_memory_get_usage}, {"move_uploaded_file", ph7_move_uploaded_file}

along with $_SESSION and $_FILES support but like i said session not complete yet but so far so good and the fact that its all embedded into a single binary is just simply amazing. Im not sure you will fully get what i mean so if not ill just say Well done

Namespaces support

On your website, you stated that you have an early prototype of PH7 with namespace support, but you have decided to drop its implementation from the build. I would like to ask if you could share the version with namespace support available?

If you do not want to publish it to the public, please let me know via PM where can I find the version with namespaces.

Thank you!

Add foreign class

Is it possible to add foreign class into PH7? I know there is ph7_create_function that allows to add foreign function. Same available for constant. Can be done for class too?

Cleaner compiles (with diffs)

In Solaris, MAP_FILE doesn't exist, so I added this:

 typedef unsigned long long int sxu64; /* 64 bits(8 bytes) unsigned int64 */
 #endif /* _MSC_VER */
+
+/* Solaris additions */
+#ifndef MAP_FILE
+# define MAP_FILE    0
+#endif
+
 /* Signature of the consumer routine */
 typedef int (*ProcConsumer)(const void *,unsigned int,void *);

The function flock() doesn't seem to exist there. The best solution would be to use some other mechanism, but for now I simply disabled it:

@@ -25318,8 +25327,13 @@
 /* int (*xLock)(void *,int) */
 static int UnixFile_Lock(void *pUserData,int lock_type)
 {
-   int fd = SX_PTR_TO_INT(pUserData);
    int rc = PH7_OK; /* cc warning */
+#ifdef SOLARIS
+   (void) pUserData;
+   (void) lock_type;
+#else
+   int fd = SX_PTR_TO_INT(pUserData);
+
    if( lock_type < 0 ){
        /* Unlock the file */
        rc = flock(fd,LOCK_UN);
@@ -25332,6 +25346,7 @@
            rc = flock(fd,LOCK_SH);
        }
    }
+#endif
    return !rc ? PH7_OK : -1;
 }
 /* ph7_int64 (*xTell)(void *) */

Gcc doesn't like large constants without a suffix:

@@ -875,8 +881,8 @@
 #define SXU16_HIGH      0xFFFF
 #define SXI32_HIGH      0x7FFFFFFF
 #define SXU32_HIGH      0xFFFFFFFF
-#define SXI64_HIGH      0x7FFFFFFFFFFFFFFF
-#define SXU64_HIGH      0xFFFFFFFFFFFFFFFF 
+#define SXI64_HIGH      0x7FFFFFFFFFFFFFFFLL
+#define SXU64_HIGH      0xFFFFFFFFFFFFFFFFUL
 #if !defined(TRUE)
 #define TRUE 1
 #endif

These are related to the previous, to avoid duplication:

@@ -32846,7 +32861,7 @@
            /* Ticket 1433-003 */
            if( longvalue < 0 ){
                /* Overflow */
-               longvalue= 0x7FFFFFFFFFFFFFFF;
+               longvalue= SXI64_HIGH;
            }
             prefix = '-';
           }else if( flag_plussign )  prefix = '+';

@@ -32858,7 +32873,7 @@
                /* Ticket 1433-003 */
                if( longvalue < 0 ){
                    /* Overflow */
-                   longvalue= 0x7FFFFFFFFFFFFFFF;
+                   longvalue= SXI64_HIGH;
                }
            }
            prefix = 0;

@@ -55279,7 +55296,7 @@
            /* Ticket 1433-003 */
            if( iVal < 0 ){
                /* Overflow */
-               iVal= 0x7FFFFFFFFFFFFFFF;
+               iVal= SXI64_HIGH;
            }
             prefix = '-';
           }else if( flag_plussign )  prefix = '+';

@@ -55291,7 +55308,7 @@
                /* Ticket 1433-003 */
                if( iVal < 0 ){
                    /* Overflow */
-                   iVal= 0x7FFFFFFFFFFFFFFF;
+                   iVal= SXI64_HIGH;
                }
            }
            prefix = 0;

To be able to compile with -Wwrite-strings, a few obvious ones are needed:

@@ -5034,7 +5040,7 @@
 {
    SyBlob *pWorker = &pVm->sWorker;
    SyString *pFile;
-   char *zErr;
+   const char *zErr;
    sxi32 rc;
    if( !pVm->bErrReport ){
        /* Don't bother reporting errors */

@@ -5083,7 +5089,7 @@
 {
    SyBlob *pWorker = &pVm->sWorker;
    SyString *pFile;
-   char *zErr;
+   const char *zErr;
    sxi32 rc;
    if( !pVm->bErrReport ){
        /* Don't bother reporting errors */

@@ -22083,7 +22092,7 @@
    const ph7_io_stream *pStream;
    struct csv_data sCsv;
    io_private *pDev;
-   char *zEol;
+   const char *zEol;
    int eolen;
    if( nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_array(apArg[1]) ){
        /* Missing/Invalid arguments,return FALSE */

@@ -22083,7 +22092,7 @@
    const ph7_io_stream *pStream;
    struct csv_data sCsv;
    io_private *pDev;
-   char *zEol;
+   const char *zEol;
    int eolen;
    if( nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_array(apArg[1]) ){
        /* Missing/Invalid arguments,return FALSE */

@@ -32603,8 +32618,8 @@
   sxu8 base;     /* The base for radix conversion */
   int flags;    /* One or more of SXFLAG_ constants below */
   sxu8 type;     /* Conversion paradigm */
-  char *charset; /* The character set for conversion */
-  char *prefix;  /* Prefix on non-zero values in alt format */
+  const char *charset; /* The character set for conversion */
+  const char *prefix;  /* Prefix on non-zero values in alt format */
 };
 typedef struct SyFmtConsumer SyFmtConsumer;
 struct SyFmtConsumer

@@ -32868,7 +32883,7 @@
         }
         bufpt = &buf[SXFMT_BUFSIZ-1];
         {
-          register char *cset;      /* Use registers for speed */
+          register const char *cset;      /* Use registers for speed */
           register int base;
           cset = infop->charset;
           base = infop->base;

@@ -32883,7 +32898,8 @@
         }
         if( prefix ) *(--bufpt) = prefix;               /* Add sign */
         if( flag_alternateform && infop->prefix ){      /* Add "0" or "0x" */
-          char *pre, x;
+          const char *pre;
+         char x;
           pre = infop->prefix;
           if( *bufpt!=pre[0] ){
             for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;

@@ -54996,8 +55012,8 @@
   sxu8 base;     /* The base for radix conversion */
   int flags;    /* One or more of PH7_FMT_FLAG_ constants below */
   sxu8 type;     /* Conversion paradigm */
-  char *charset; /* The character set for conversion */
-  char *prefix;  /* Prefix on non-zero values in alt format */
+  const char *charset; /* The character set for conversion */
+  const char *prefix;  /* Prefix on non-zero values in alt format */
 };
 #ifndef PH7_OMIT_FLOATING_POINT
 /*

@@ -55301,7 +55318,7 @@
         }
         zBuf = &zWorker[PH7_FMT_BUFSIZ-1];
         {
-          register char *cset;      /* Use registers for speed */
+          register const char *cset;      /* Use registers for speed */
           register int base;
           cset = pInfo->charset;
           base = pInfo->base;

@@ -55316,7 +55333,8 @@
         }
         if( prefix ) *(--zBuf) = (char)prefix;               /* Add sign */
         if( flag_alternateform && pInfo->prefix ){      /* Add "0" or "0x" */
-          char *pre, x;
+          const char *pre;
+         char x;
           pre = pInfo->prefix;
           if( *zBuf!=pre[0] ){
             for(pre=pInfo->prefix; (x=(*pre))!=0; pre++) *(--zBuf) = x;

There were a couple of more complicated places, which ideally should be handled by having a separate "char_" and a "const char_". Many of these are quite similar, so perhaps they can be refactored into something common? For now, this also works to get the compiler to shut up:

@@ -32924,7 +32940,7 @@
           while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
           while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
           if( exp>350 || exp<-350 ){
-            bufpt = "NaN";
+            bufpt = (char*) "NaN";
             length = 3;
             break;
           }

@@ -33045,7 +33061,7 @@
       case SXFMT_STRING:
         bufpt = va_arg(ap,char*);
         if( bufpt==0 ){
-          bufpt = " ";
+          bufpt = (char*) " ";
          length = (int)sizeof(" ")-1;
          break;
         }

@@ -33060,7 +33076,7 @@
        /* Symisc extension */
        SyString *pStr = va_arg(ap,SyString *);
        if( pStr == 0 || pStr->zString == 0 ){
-            bufpt = " ";
+            bufpt = (char*) " ";
             length = (int)sizeof(char);
             break;
        }

@@ -55240,7 +55257,7 @@
                zBuf = (char *)ph7_value_to_string(pArg,&length);
            }
            if( length < 1 ){
-               zBuf = " ";
+               zBuf = (char*) " ";
                length = (int)sizeof(char);
            }
            if( precision>=0 && precision<length ){

@@ -55369,7 +55387,7 @@
           while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
           while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
           if( exp>350 || exp<-350 ){
-            zBuf = "NaN";
+            zBuf = (char*) "NaN";
             length = 3;
             break;
           }

Also, sizeof() is unsigned, while ph7_int64 is signed, so these two are needed (the second one is nicer, I think):

@@ -20543,7 +20549,9 @@
     * limit is reached.
     */
    for(;;){
-       n = pStream->xRead(pDev->pHandle,zBuf,(nMaxLen > 0 && nMaxLen < sizeof(zBuf)) ? nMaxLen : si
zeof(zBuf));
+       n = pStream->xRead(pDev->pHandle, zBuf,
+           (nMaxLen > 0 && nMaxLen < (ph7_int64) sizeof(zBuf)) ?
+               nMaxLen : (ph7_int64) sizeof(zBuf));
        if( n < 1 ){
            /* EOF or IO error */
            break;

@@ -21418,8 +21426,9 @@
    /* Perform the requested operation */
    nRead = 0;
    for(;;){
+       ph7_int64 zBufSz = (ph7_int64) sizeof(zBuf);
        n = pStream->xRead(pHandle,zBuf,
-           (nMaxlen > 0 && (nMaxlen < sizeof(zBuf))) ? nMaxlen : sizeof(zBuf));
+           (nMaxlen > 0 && (nMaxlen < zBufSz)) ? nMaxlen : zBufSz);
        if( n < 1 ){
            /* EOF or IO error,break immediately */
            break;

Unable to include more than 1 file from PH7_VM_CONFIG_IMPORT_PATH.

Hello,

I discovered this strange, obscure bug where the second include/require of a file from the PH7_VM_CONFIG_IMPORT_PATH doesn't work. After some investigation, I found that when PH7_StreamOpenHandle is called for the second include, SySetGetNextEntry returns garbage on the second round of the while loop (first time it correctly returns ./).

I just can't seem to find the root of this problem, though. My temporary mitigation is to chdir to the import path, but that's just not right.

Thanks

Using latest version built with -DPH7_ENABLE_THREADS -DMAP_FILE=0x0001. Run on Ubuntu 18.04 x64.

non-amalgam code should be available

The source code in its entirety should be available to encourage forks and community development; it is difficult to work with a single giant code file.

Functions / methods with same name allowed without warnings. Method attributes not considered.

`<?php
class test {

    function __construct($q) {
            echo "Constructor $q";
    }

    function a($a) {
            echo 'A';
    }

}

$x = new test('test');
$x->a();

?>`

I have created the following code snippet, and it works as expected. However I am missing any warning message about missing parameter. Since it is not optional, as there is no default value assigned to it, I believe there should be at least some information about that mistake.
What is more, if I implement additional a($a, $b) function which takes two arguments, the same code will execute the first function with matching name. I think that best solution would be that $x->a() returning NULL instead of executing some method/function that does not match parameters number.

Same happens if there are several methods with the same name / same number of parameters.
Only first declared is working and there is no information about duplicate function name.

In addition I were able to launch protected & private method from outside of class they were implemented.

Minor doc mis-type

First things first, very cool! Thanks for posting!

Was reading through the docs and noticed that in the examples for the eq / ne operators there's a minor error (I think).

http://ph7.symisc.net/features.html#eq_op

That last example comparison...

//Append a single space to the first operand
var_dump(' 255 ' ne '255'); //bool(FALSE) (Not of the same length)

I'm about 80% sure that would return TRUE. Would submit a pull but I don't think those docs are on GitHub. Obviously, this renders the whole thing useless until fixed. /s

SIGSEGV on ubuntu 12.04 LTS with gcc -O flags

while trying the official docs example. experienced the following error.

Steps to reproduce:

cat /etc/issue
Ubuntu 12.04.4 LTS \n \l
wget http://www.symisc.net/downloads/ph7-amalgamation-2001004.zip
unzip ph7-amalgamation-2001004.zip
wget http://www.symisc.net/downloads/ph7_intro.c
gcc -W -Wall -O6 -o ph7_test ph7_intro.c ph7.c

./ph7_test 
Segmentation fault (core dumped)

Strace below

execve("./ph7_test", ["./ph7_test"], [/* 51 vars */]) = 0
brk(0)                                  = 0x10b7000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc2dc292000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=107616, ...}) = 0
mmap(NULL, 107616, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fc2dc277000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200\30\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1815224, ...}) = 0
mmap(NULL, 3929304, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc2dbcb2000
mprotect(0x7fc2dbe67000, 2097152, PROT_NONE) = 0
mmap(0x7fc2dc067000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b5000) = 0x7fc2dc067000
mmap(0x7fc2dc06d000, 17624, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fc2dc06d000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc2dc276000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc2dc275000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc2dc274000
arch_prctl(ARCH_SET_FS, 0x7fc2dc275700) = 0
mprotect(0x7fc2dc067000, 16384, PROT_READ) = 0
mprotect(0x681000, 4096, PROT_READ)     = 0
mprotect(0x7fc2dc294000, 4096, PROT_READ) = 0
munmap(0x7fc2dc277000, 107616)          = 0
brk(0)                                  = 0x10b7000
brk(0x10e0000)                          = 0x10e0000
open("/dev/urandom", O_RDONLY)          = 3
read(3, ".\256\345\242\352\210?\233V\312+%\334R\16n\306F\370v\2\36@7E\355\245\2762bP\37"..., 256) = 256
brk(0x1105000)                          = 0x1105000
brk(0x1102000)                          = 0x1102000
brk(0x1124000)                          = 0x1124000
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)

gcc version

gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Works when -O1, -O2 flags are used.
Fails when -O3 or higher are used.

maybe update docs or something if its trivial.

ord() function is incorrectly implemented

Function ord() known from PHP and Delphi/Free Pascal/Lazarus should return ascii code for a given char. And ASCII codes are 0-255. So the code below under PHP returns 197:

<?php
$str = 'ล›';
echo ord($str[0]);

However under PH7 it returns -59.
Looks like PH7 stores characters not as an array of UINT8 but an array of INT8. Why is that? Any chance for a fix?

Serialization of arrays does not work as expected

$GLOBALS is an associative array which contains the following value:
Array(10) { [_SERVER] => Array(1) { [SCRIPT_FILENAME] => test.ph7 } [_GET] => Array(0) { } [_POST] => Array(0) { } [_FILES] => Array(0) { } [_COOKIE] => Array(0) { } [_SESSION] => Array(0) { } [_REQUEST] => Array(0) { } [_ENV] => Array(0) { } [_HEADER] => Array(0) { } [argv] => Array(0) { } }

Anyway the following code:
var_dump(unserialize(serialize($GLOBALS)));
produces the following output:
array(10) { [0] => array(1) { [0] => string(8 'test.ph7') } [1] => array(0) { } [2] => array(0) { } [3] => array(0) { } [4] => array(0) { } [5] => array(0) { } [6] => array(0) { } [7] => array(0) { } [8] => array(0) { } [9] => array(0) { } }

As you can see, they array somehow got converted from associative to numeric.

mutex memory leak in ph7_vm_release (with patch)

Latest clone, on Debian 7 i686 (x32), gcc 4.7.2 (Debian 4.7.2-5)
-DPH7_ENABLE_MATH_FUNC -DPH7_ENABLE_THREADS

Valgrind reports a definite memory loss of 112 bytes.
The loss starts when a recursive mutex is created in ProcessScript (60601).
When ph7_vm_release is called, the mutex is not released.

This patch fixes that.

---------8<-----------------------------------8<---------------------------------------------8<--------------------------
--- ph7.oem 2015-03-15 11:58:17.430116368 -0400
+++ ph7.c 2015-03-15 11:55:36.150961417 -0400
@@ -60873,6 +60873,8 @@
 #if defined(PH7_ENABLE_THREADS)
   /* Leave VM mutex */
   SyMutexLeave(sMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
+  /* free VM mutex PATCH by SGM 15-MAR-2015 */
+  SyMutexRelease(sMPGlobal.pMutexMethods,pVm->pMutex);
 #endif
  if( rc == PH7_OK ){
    /* Unlink from the list of active VM */
----------------------------->8------------------------->8-------------------------------------->8-----------------------

Hope this helps.

Recursive function call stuck?

I have tried to benchmark PH7 Engine and compare it to other interpreters available on the open-source market. I used the following snippet of code and it equivalent in different <?php

<?php

function fibR($n)
{
    if ($n < 2) return $n;
    return (fibR($n-2) + fibR($n-1));
}

function fibI($n)
{
    $last = 0;
    $cur = 1;
    --$n;
    while($n > 0)
    {
        --$n;
        $tmp = $cur;
        $cur = $last + $cur;
        $last = $tmp;
    }
    return $cur;
}

$N = 43;
echo 'fibR: ' . fibR($N) . "\n";
echo 'fibI: ' . fibI($N) . "\n";

First of all I tried Wren, which aims to be very fast. It executed the fibR() function in less than 2 minutes. On the other hand fibI() function executed over 1 hour. Having this tested, I checked what is the PH7 Engine performance. fibI() function executes immediately (around 0.007s). When comparing to Wren - it is extremely fast! Unfortunately I have not managed to execute fibR() successfully. I had to break script execution after 5 hours on 6th gen Core i7 CPU! Code looks good and works well in Zend PHP (fibR() executes around 2mins, fibI executes in less than 1s).
What's wrong with PH7?

Included code behaves differently

$ cat x.php
<?php
final class X {
  public static $variable = "Hello";
}

function bootstrap() {
  echo "Bootstrapping...\n";
  X::$variable.= "World";
}

bootstrap();
var_dump(X::$variable);

$ ./ph7.exe x.php
Bootstrapping...
string(10 'HelloWorld')

So far, so good. Now let x.php run inside an include() context:

$ cat hello.php
<?php
include("x.php");

$ ./ph7.exe hello.php
Bootstrapping...
null

Enabling errors yields the following:

Error: Cannot perform assignment on a constant class attribute,PH7 is loading NULL

Warnings while comparing signed and unsigned long integers

I'm on OSX 10.11.6 (El Capitan), using GCC (LLVM/clang-703.0.31) and during compilation, I'm seeing the following, relatively harmless, integer comparison warnings:

2 warnings generated.
ph7.c:20546:65: warning: comparison of integers of different signs: 'ph7_int64' (aka 'long long') and 'unsigned long' [-Wsign-compare]
            n = pStream->xRead(pDev->pHandle,zBuf,(nMaxLen > 0 && nMaxLen < sizeof(zBuf)) ? nMaxLen : sizeof(zBuf));
                                                                  ~~~~~~~ ^ ~~~~~~~~~~~~
ph7.c:21422:29: warning: comparison of integers of different signs: 'ph7_int64' (aka 'long long') and 'unsigned long' [-Wsign-compare]
                    (nMaxlen > 0 && (nMaxlen < sizeof(zBuf))) ? nMaxlen : sizeof(zBuf));
                                     ~~~~~~~ ^ ~~~~~~~~~~~~

Could the warnings be resolved by casting the 'nMaxlen' variable, in the '(nMaxlen < sizeof(zBuf))' comparison to be 'unsigned'? I'm assuming the sign will make no difference, given the initial positive check (i.e. 'nMaxlen > 0').

In this post by Jamie Bullock@stackoverflow, he offers a simple example of how to better handle this type comparison mismatch:

Actually, I don't think turning off the compiler warning is the right solution, since comparing an int and an unsigned long introduces a subtle bug.

For example:

unsigned int a = UINT_MAX; // 0xFFFFFFFFU == 4,294,967,295 
signed int b = a; // 0xFFFFFFFF == -1

for (int i = 0; i < b; ++i)
{
    // the loop will have zero iterations because i < b is always false!
}

Basically if you simply cast away (implicitly or explicitly) an unsigned int to an int your code will behave incorrectly if the value of your unsigned int is greater than INT_MAX.

The correct solution is to cast the signed int to unsigned int and to also compare the signed int to zero, covering the case where it is negative:

unsigned int a = UINT_MAX; // 0xFFFFFFFFU == 4,294,967,295 

for (int i = 0; i < 0 || (unsigned)i < a; ++i)
{
    // The loop will have UINT_MAX iterations
}

I do realise I could simply suppress or ignore the warnings.

How to create a class with methods?

Hey, remember me? Been quite a while.

I have started to work with V and I am looking to build a tool that needs a scripting language - and that is how i randomly found ph7 again. Now, I would love to know if there is a way to create classes and methods? From what I remember, namespaces were never really implemented... So I am not even gonna ask how to add methods to namespaces just yet :)

Kind regards,
Ingwie

PH7 into Embedded Web Server (missing examples)

Hello Everybody,

I am porting PH7 to ESP8266 and other MCU. I am lloking for the examples:- ph7_http and ph7_webserver the link to them from the PH7 online/manual are dead links. So please help!

I have managed to compile PH7 with ESP8266 SDK (based on ph7_cgi.c) but I am hitting a deadlock getting it to work after flashing it into the micro-controller. I think seeing those examples will help. Many thanks!

I have already sent a request email from my gmail account to [email protected] and also through the forum and to chm

Please help!

God blesses!!!

Best regards,
Sanyaade

Can't call functions in instance of class instantiated in require()ed file

I'm defining a class in a require()'ed file and making an instance in it, but in the parent file I get an error when trying to call the functions. On some level it knows they are there since if I check the instance with get_class_methods() it shows the methods.

I have attached a minimal example and if I execute test.php I get this error:

test.inc.php Warning: Call to undefined function '[__TestClass@Hello_eljexvpoer]',NULL will be returned

Oddly enough this is a distinctly different error than if I try to call a function that doesn't actually exist like $inst->Hello2():

test.inc.php Error: Undefined class method 'TestClass->Hello2',PH7 is loading NULL
test.inc.php Warning: Invalid function name,NULL will be returned

test.zip

Cannot extend from class inside include

Define a class inside an include to see this happen:

$ cat main.php
<?php
include("x.php");

class Y extends X {

}

var_dump(new Y());

$ cat x.php
<?php
class X {

}

$ ./ph7.exe hello.php
hello.php: 4 Error: Inexistant base class 'X'
Compile error

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.