2006-09-11 11:23:56 +00:00
/*
2006-09-07 20:00:23 +00:00
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2005 / 2006 , Anthony Minessale II < anthmct @ yahoo . com >
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II < anthmct @ yahoo . com >
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
2006-09-11 11:23:56 +00:00
*
2006-09-07 20:00:23 +00:00
* Anthony Minessale II < anthmct @ yahoo . com >
2006-09-10 23:19:15 +00:00
* Brian Fertig < brian . fertig @ convergencetek . com >
2006-09-12 01:23:53 +00:00
* Steph Fox < steph @ zend . com >
*
2006-09-07 20:00:23 +00:00
*
* mod_php . c - - PHP Module
*
*/
2006-09-08 00:51:40 +00:00
# ifndef _REENTRANT
# define _REENTRANT
# endif
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
2006-09-12 03:20:56 +00:00
# ifdef _MSC_VER
//disable warnings for malformed header files
# pragma warning(push)
# pragma warning(disable:4127 4311 4133 4244 4201)
# define _USE_32BIT_TIME_T 1
# endif
2006-09-08 03:09:26 +00:00
# include <sapi/embed/php_embed.h>
2006-09-11 11:23:56 +00:00
2006-09-12 03:20:56 +00:00
# ifdef _MSC_VER
# pragma warning(pop)
2006-09-11 11:23:56 +00:00
# endif
2006-09-10 23:19:15 +00:00
2006-09-12 03:20:56 +00:00
# ifdef ZTS
zend_compiler_globals * compiler_globals ;
zend_executor_globals * executor_globals ;
php_core_globals * core_globals ;
sapi_globals_struct * sapi_globals ;
# endif
2006-09-07 20:00:23 +00:00
2006-09-08 00:51:40 +00:00
# include <switch.h>
2006-09-07 20:00:23 +00:00
const char modname [ ] = " mod_php " ;
2006-09-10 23:19:15 +00:00
static int sapi_mod_php_ub_write ( const char * str , unsigned int str_length TSRMLS_DC )
2006-09-11 11:23:56 +00:00
{
2006-09-12 03:20:56 +00:00
char buffer [ 4096 ] ;
unsigned int i ;
int j = 0 ;
FILE * fp = fopen ( " mod_php.log " , " a " ) ;
fwrite ( str , str_length , sizeof ( char ) , fp ) ;
fclose ( fp ) ;
for ( i = 0 ; i < str_length ; i + + ) {
buffer [ j + + ] = str [ i ] ;
if ( str [ i ] = = 10 ) { /* new line */
buffer [ j ] = 0 ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " %s " , buffer ) ;
j = 0 ;
}
else if ( str [ i ] = = 0 ) { /* null character */
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " %s " , buffer ) ;
j = 0 ;
}
if ( j = = 4095 ) { /* don't overfill buffer */
buffer [ j ] = 0 ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " %s " , buffer ) ;
j = 0 ;
}
}
if ( j ) { /* stuff left over */
buffer [ j ] = 0 ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " %s " , buffer ) ;
}
return str_length ;
2006-09-10 23:19:15 +00:00
}
void mod_php_error_handler ( int type , const char * error_filename , const uint error_lineno , const char * format , va_list args )
{
2006-09-12 03:20:56 +00:00
char * buffer ;
int buffer_len ;
TSRMLS_FETCH ( ) ;
buffer_len = vspprintf ( & buffer , PG ( log_errors_max_len ) , format , args ) ;
if ( ( EG ( error_reporting ) & type | | ( type & E_CORE ) ) & & ( PG ( log_errors ) | | PG ( display_errors ) ) ) {
char * error_type_str ;
switch ( type ) {
case E_ERROR :
case E_CORE_ERROR :
case E_COMPILE_ERROR :
case E_USER_ERROR :
error_type_str = " Fatal error " ;
break ;
case E_WARNING :
case E_CORE_WARNING :
case E_COMPILE_WARNING :
case E_USER_WARNING :
error_type_str = " Warning " ;
break ;
case E_PARSE :
error_type_str = " Parse error " ;
break ;
case E_NOTICE :
case E_USER_NOTICE :
error_type_str = " Notice " ;
break ;
default :
error_type_str = " Unknown error " ;
break ;
}
if ( PG ( log_errors ) ) {
char * log_buffer ;
spprintf ( & log_buffer , 0 , " PHP %s: %s in %s on line %d " , error_type_str , buffer , error_filename , error_lineno ) ;
php_log_err ( log_buffer TSRMLS_CC ) ;
efree ( log_buffer ) ;
}
if ( PG ( display_errors ) ) {
char * prepend_string = INI_STR ( " error_prepend_string " ) ;
char * append_string = INI_STR ( " error_append_string " ) ;
char * error_format = " %s \n %s: %s in %s on line %d \n %s " ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , error_format , STR_PRINT ( prepend_string ) , error_type_str , buffer , error_filename , error_lineno , STR_PRINT ( append_string ) ) ;
}
}
// Bail out if we can't recover
switch ( type ) {
case E_CORE_ERROR :
case E_ERROR :
//case E_PARSE: the parser would return 1 (failure), we can bail out nicely
case E_COMPILE_ERROR :
case E_USER_ERROR :
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " \n PHP: %s exiting \n " , error_filename ) ;
EG ( exit_status ) = 255 ;
2006-09-10 23:19:15 +00:00
# if MEMORY_LIMIT
2006-09-12 03:20:56 +00:00
// restore memory limit
AG ( memory_limit ) = PG ( memory_limit ) ;
2006-09-10 23:19:15 +00:00
# endif
2006-09-12 03:20:56 +00:00
efree ( buffer ) ;
zend_bailout ( ) ;
return ;
}
// Log if necessary
if ( PG ( track_errors ) & & EG ( active_symbol_table ) ) {
pval * tmp ;
ALLOC_ZVAL ( tmp ) ;
INIT_PZVAL ( tmp ) ;
Z_STRVAL_P ( tmp ) = ( char * ) estrndup ( buffer , buffer_len ) ;
Z_STRLEN_P ( tmp ) = buffer_len ;
Z_TYPE_P ( tmp ) = IS_STRING ;
zend_hash_update ( EG ( active_symbol_table ) , " php_errormsg " , sizeof ( " php_errormsg " ) , ( void * * ) & tmp , sizeof ( pval * ) , NULL ) ;
}
efree ( buffer ) ;
2006-09-10 23:19:15 +00:00
}
static void mod_php_log_message ( char * message )
{
2006-09-12 03:20:56 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " %s \n " , message ) ;
2006-09-10 23:19:15 +00:00
}
2006-09-11 11:23:56 +00:00
typedef void ( * sapi_error_function_t ) ( int type , const char * error_msg , . . . ) ;
2006-09-10 23:19:15 +00:00
2006-09-11 11:23:56 +00:00
static void php_function ( switch_core_session_t * session , char * data )
{
2006-09-12 03:20:56 +00:00
char * uuid = switch_core_session_get_uuid ( session ) ;
size_t ulen = strlen ( uuid ) ;
size_t len = strlen ( ( char * ) data ) + ulen + 2 ;
char * mydata = switch_core_session_alloc ( session , len ) ;
int argc , retval ;
char * argv [ 5 ] ;
char php_code [ 1024 ] ;
void * * * tsrm_ls = NULL ;
zend_file_handle script ;
zval * php_uuid ;
snprintf ( mydata , len , " %s %s " , uuid , data ) ;
argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ;
sprintf ( php_code , " uuid= \" %s \" ; include( \" %s \" ); \n " , argv [ 0 ] , argv [ 1 ] ) ;
2006-09-11 11:23:56 +00:00
sprintf ( php_code , " %s %s " , data , uuid ) ;
2006-09-12 03:20:56 +00:00
script . type = ZEND_HANDLE_FP ;
script . filename = data ;
script . opened_path = NULL ;
script . free_filename = 0 ;
script . handle . fp = fopen ( script . filename , " rb " ) ;
2006-09-11 11:23:56 +00:00
// Initialize PHPs CORE
php_embed_init ( argc , argv , & tsrm_ls ) ;
// Return All of the DEBUG crap to the console and/or a log file
2006-09-12 03:20:56 +00:00
php_embed_module . ub_write = sapi_mod_php_ub_write ;
php_embed_module . log_message = mod_php_log_message ;
php_embed_module . sapi_error = ( sapi_error_function_t ) mod_php_error_handler ;
2006-09-11 11:23:56 +00:00
// Let the nice people know we are about to start their script
2006-09-12 03:20:56 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " Starting Script %s \n " , data ) ;
2006-09-11 11:23:56 +00:00
// Force $uuid and $session to exist in PHPs memory space
MAKE_STD_ZVAL ( php_uuid ) ;
2006-09-12 03:20:56 +00:00
# ifdef _MSC_VER
//disable warnings for malformed macros from header files
# pragma warning(push)
# pragma warning(disable:4127 4267)
# endif
2006-09-11 11:23:56 +00:00
ZVAL_STRING ( php_uuid , uuid , 1 ) ;
ZEND_SET_SYMBOL ( & EG ( symbol_table ) , " uuid " , php_uuid ) ;
2006-09-12 03:20:56 +00:00
# ifdef _MSC_VER
# pragma warning(pop)
# endif
2006-09-11 11:23:56 +00:00
// Execute the bloody script
2006-09-12 03:20:56 +00:00
retval = php_execute_script ( & script TSRMLS_CC ) ;
2006-09-11 11:23:56 +00:00
// Clean up after PHP and such
2006-09-12 03:20:56 +00:00
php_embed_shutdown ( tsrm_ls ) ;
2006-09-11 12:06:27 +00:00
// Return back to the Dialplan
2006-09-12 03:20:56 +00:00
2006-09-11 11:23:56 +00:00
// Buh bye now!
}
2006-09-10 23:19:15 +00:00
2006-09-11 11:23:56 +00:00
static const switch_application_interface_t php_application_interface = {
2007-02-26 21:38:10 +00:00
/*.interface_name */ " php " ,
/*.application_function */ php_function ,
NULL , NULL , NULL ,
/* flags */ SAF_NONE , /* should we support no media mode here? If so, we need to detect the mode, and either disable the media functions or indicate media if/when we need */
/*.next*/ NULL
2006-09-11 11:23:56 +00:00
} ;
2006-09-10 23:19:15 +00:00
2006-09-11 11:23:56 +00:00
static switch_loadable_module_interface_t php_module_interface = {
/*.module_name */ modname ,
/*.endpoint_interface */ NULL ,
/*.timer_interface */ NULL ,
/*.dialplan_interface */ NULL ,
/*.codec_interface */ NULL ,
/*.application_interface */ & php_application_interface ,
/*.api_interface */ NULL ,
/*.file_interface */ NULL ,
/*.speech_interface */ NULL ,
/*.directory_interface */ NULL
2006-09-10 23:19:15 +00:00
} ;
SWITCH_MOD_DECLARE ( switch_status_t ) switch_module_load ( const switch_loadable_module_interface_t * * module_interface , char * filename )
{
2006-09-12 03:20:56 +00:00
void * * * tsrm_ls = NULL ;
2006-09-10 23:19:15 +00:00
2006-09-12 03:20:56 +00:00
/* connect my internal structure to the blank pointer passed to me */
* module_interface = & php_module_interface ;
2006-09-10 23:19:15 +00:00
2006-09-11 11:23:56 +00:00
# ifdef ZTS
tsrm_startup ( 1 , 1 , 0 , NULL ) ;
compiler_globals = ts_resource ( compiler_globals_id ) ;
executor_globals = ts_resource ( executor_globals_id ) ;
core_globals = ts_resource ( core_globals_id ) ;
sapi_globals = ts_resource ( sapi_globals_id ) ;
tsrm_ls = ts_resource ( 0 ) ;
# endif
2006-09-12 03:20:56 +00:00
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
2006-09-10 23:19:15 +00:00
}
2006-09-11 11:23:56 +00:00
/*
2006-09-11 12:06:27 +00:00
//Called when the system shuts down
2006-09-11 11:23:56 +00:00
SWITCH_MOD_DECLARE ( switch_status ) switch_module_shutdown ( void )
{
return SWITCH_STATUS_SUCCESS ;
}
2006-09-11 12:06:27 +00:00
//If it exists, this is called in it's own thread when the module-load completes
2006-09-11 11:23:56 +00:00
SWITCH_MOD_DECLARE ( switch_status ) switch_module_shutdown ( void )
{
return SWITCH_STATUS_SUCCESS ;
}
2006-09-11 12:06:27 +00:00
*/
2006-11-27 22:30:48 +00:00
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : nil
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 expandtab :
*/