www.gusucode.com > 同城苏州黄页系统php源码程序 > lib/http_soap.class.php

    <?
######################################

// 默认 或 参数 $_REQUEST['sync']=true , 使用 异步方式
ignore_user_abort( empty($_REQUEST['sync']) or !$_REQUEST['sync'] );

######################################

define( '__DEFAULT_ENDTIME', 600 );
define( '__OBJID_REGEXP', "/^(\w+)\-(\d+\.\d+)\-(\d+)$/" );

if( !class_exists('base') )
	include dirname(__FILE__).'/base.class.php' ;
if( !class_exists('http') )
	include dirname(__FILE__).'/http.class.php' ;


	
class msg
{
	var $puter ;
	var $msg ;

	function msg( $msg, $puter )
	{
		$this->puter = $puter ;
		$this->msg = $msg ;
	}

	function out()
	{
		if( empty($this->msg) )
			return false ;
		return "[{$this->puter}]\r\n{$this->msg}\r\n\r\n" ;
	}
}
class http_soap_exception
{
	var $msgs 			 = array() ;

	function http_soap_exception()
	{
	}

	function put( $theMsg )
	{
		if( !is_object($theMsg) or get_class($theMsg)!='msg' )
			return false;
		$this->msgs[] = $theMsg ;
		return true ;
	}
	
	function get()
	{
		if( !count($this->msgs) )
			return false;

		return array_shift( $this->msgs );
	}

	function out_msg()
	{
		$outStr = '' ;
		while( $theMsg = $this->get() )
			$outStr.= $theMsg->out() ;
		return $outStr ;
	}
	
	function load( $srcstr )
	{
		if( !$exObj = @unserialize($srcstr) )
			return false ;

		if( !is_object($exObj) or get_class($exObj)!='http_soap_exception' )
			return false ;

		while( $theMsg = $exObj->get() )
			$this->put( $theMsg ) ;

		return true ;
	}

}

$http_soap_exception = &new http_soap_exception();

class http_soap_base extends base
{
	var $class_name ;
	var $ObjID ;							// 对象 id
	var $class_dir ;
	var $obj_serialize_dir ;
	
	var $readonly 		= false;

	var $concrete_class_consr_parameter ;
	var $after_load_invoke_func ;
	var $after_load_invoke_param ;
	
	var $idle_time = __DEFAULT_ENDTIME ;
	var $exception ;

	/**
	 * 用于在 _create() 和 _load() 之前 载入 所请求对象的  类的定义文件
	 *
	 */
	function _include_class_define()
	{

		$class_flie = "{$this->class_dir}{$this->class_name}.class.php" ;

		if( !file_exists($class_flie) or !is_file($class_flie) )
		{
			$this->put_exception_msg("No class define file on server. The class name is:{$this->class_name}") ;
			return false ;
		}

		include_once( $class_flie );							// 定义 类

		if( !class_exists($this->class_name) )
		{
			$this->put_exception_msg("Class no defined. The class name is:{$this->class_name}") ;
			return false ;
		}

		
		return true ;
	}

	function put_exception_msg( $msg )
	{
		if( empty($msg) )
			return false ;
		$this->exception->put( new msg($msg, 'Http Soap User Class') ) ;
	}

	function http_soap_base( $if_conn_db = false /*$concrete_class_consr_parameter = array()*/ )
	{
		$this->base( $if_conn_db );								// 初始化 基类,但不连接数据库
		$this->class_dir 			= $this->root_path . 'lib/';
		$this->obj_serialize_dir 	= $this->root_path . 'soap_obj_serialize/';

		global $http_soap_exception;
		if( is_object($http_soap_exception) )
			$this->exception = & $http_soap_exception ;

		// $this->concrete_class_consr_parameter = serialize( $concrete_class_consr_parameter ) ;
	}

	/**
	 * 创建新的对象
	 *
	 */
	function create( $class_name, $constructor_parameter=array() )
	{
		$this->class_name = $class_name ;
		
		// 创建 对象ID 
		if( empty($this->ObjID) )
			$this->ObjID =  $this->_create_obj_id() ;

		// 包含 类定义文件
		if( !$this->_include_class_define() )
			return false ;

		// 创建新对象
		$this->concrete_class_consr_parameter = base64_encode(serialize($constructor_parameter)) ;
		$Obj = & new $class_name( $constructor_parameter );

		$Obj->class_name				 = $this->class_name ;
		$Obj->ObjID						 = $this->ObjID ;
		$Obj->class_dir					 = $this->class_dir ;
		$Obj->obj_serialize_dir			 = $this->obj_serialize_dir ;
		$Obj->concrete_class_consr_parameter
										 = $this->concrete_class_consr_parameter ;
		$Obj->after_load_invoke_func	 = $this->after_load_invoke_func ;
		$Obj->after_load_invoke_param	 = $this->after_load_invoke_param ;
		$exception					 	 = & $this->exception ;

		$this = $Obj ;
		$this->exception = & $exception ;
		if( !empty($_REQUEST['end_time']) )
			$this->idle_time = $_REQUEST['end_time'] ;

		return true;
	}

	/**
	 * 销毁一个对象,当一件具体的工作完成后
	 *
	 */
	function destroy( $ObjID='' )
	{
		if( !empty($ObjID) )
			$this->ObjID = $ObjID ;

		$class_flie = $this->obj_serialize_dir . $this->ObjID  ;
		if( !file_exists($class_flie) or !is_file($class_flie) )
		{
			$this->put_exception_msg( "No ObjID parameter from client." );
			return false;
		}
		$result = @unlink($class_flie);
		return  $result;
	}

	function save( $after_load_invoke_func = '', $after_load_invoke_param=array() )
	{

		# 保存状态
		$this->after_load_invoke_func = $after_load_invoke_func ;
		$this->after_load_invoke_param = $after_load_invoke_param ;
		if( !$s = serialize($this) )
			return false ;
		$s = base64_encode($s);

		# 序列化 存储到硬盘
		$now = time() ;
		$endtime = $now  +  $this->idle_time ;
		$file_content = '<'."?\r\n" ;
		$file_content.= "\$last_action			 = {$now} ;				// 该对象最后活动时间:" . date('Y.m.d G:i:s',$now) . " \r\n" ;
													// 最后活跃时间
		$file_content.= "\$end_time				 = {$endtime} ;				// 该对象空闲终止时间:" . date('Y.m.d G:i:s',$endtime) . " \r\n" ;
													// 终止时间
	
		$file_content.= "\$constructor_parameter	 = '{$this->concrete_class_consr_parameter}' ;\r\n";
													// 构造函数参数
		$file_content.= "\$Obj_serialize			 = '{$s}' ;";
													// 对象 序列化 存储
		$file_content.= "\r\n?".'>';

		return file_put_contents( $this->obj_serialize_dir . $this->ObjID, $file_content );		
	}
	
	function load( $ObjID='' )
	{
		if( !empty($ObjID) )
			$this->ObjID = $ObjID ;

		if( !$Obj_info = get_Obj_info($this->ObjID) )
		{
			$this->put_exception_msg("The ObjID is invalid. The ObjID is:{$this->ObjID}") ;
			return false ;
		}

		// 载入 存储文件
		$serialize_file = $this->obj_serialize_dir . $this->ObjID ;
		if( !file_exists( $serialize_file ) or !is_file($serialize_file) )
		{
			$this->put_exception_msg("No Object serialize file on server. The Object ID is:{$this->ObjID}") ;
			return false;
		}

		include $serialize_file ;
		$consructor_parameter = @base64_decode($constructor_parameter);
		$consructor_parameter = @unserialize($consructor_parameter) ;
		
		if( !$consructor_parameter )
			$consructor_parameter = array();

		$this->concrete_class_consr_parameter = $consructor_parameter ;

		// 调用构造函数 初始化
		if( !$this->create( $Obj_info['class_name'], $consructor_parameter ) )
		{
			$this->put_exception_msg('Load Obj bad.') ;
			return false;
		}

		// 恢复存储前的状态
		
		if( empty($Obj_serialize) )
		{
			// echo $Obj_serialize;
			$this->put_exception_msg("The Object serialize file is empty. The Object ID is:{$this->ObjID}") ;
			return false;
		}
		$Obj_serialize = base64_decode($Obj_serialize);

		if( !$this = unserialize( $Obj_serialize ) )
		{
			$this->put_exception_msg("The Object serialize file can not unserialize. The Object ID is:{$this->ObjID}") ;
			return false;
		}

		global $http_soap_exception ;
		if( is_object($http_soap_exception) and get_class($http_soap_exception)=='http_soap_exception' )
			$this->exception = & $http_soap_exception ;

		if( empty($this->after_load_invoke_func) )
			return true;

		return true;
	
	}
	
	function _create_obj_id()
	{
		list($usec, $sec) = explode( ' ', microtime() );
		$usec = str_replace( '0.', '', $usec ) ;		
		return $this->ObjID = "{$this->class_name}-{$sec}.{$usec}-".sprintf( "%04d", rand(1,9999) ) ;
	}
}


/**
 * SOAP 客户方,用于呼叫、调用 另一台主机上的 php class
 *
 */
class http_soap_client extends http
{
	var $ObjID ;							// 对象 id
	var $readonly		= false ;
	var $soap_uri ;
	var $cient 			= 'php' ;

	var $exception ;

	var $additional 	= array() ;
	
	var $send_http_body	= '' ;
	var $recv_http_body	= '' ;

	function set_additional( $key, $value )
	{
		$this->additional[ $key ] = $value ;
	}

	function put_exception_msg( $msg )
	{
		if( empty($msg) )
			return false ;
		$this->exception->put( new msg($msg, 'Http Soap Client') ) ;
	}

	/**
	 * 创建一个客户端
	 *
	 * @param string $remove_host		远程主机
	 * @param string $api_path			远程主机上的 http_soap_server api 路径
	 */
	function http_soap_client( $remove_host, $api_path )
	{
		$this->http();
		$this->host = $remove_host ;
		$this->soap_uri = $api_path ;

		global $http_soap_exception;
		if( is_object($http_soap_exception) )
			$this->exception = &$http_soap_exception ;
		
	}

	/**
	 * 在另一台主机上,创建一个 php 对象。 创建的对象,会在所在主机上保存,直到调用 http_soap_client::destroy() , 或 到该对象生命期 自行结束
	 *
	 * @param string $class_name	需要创建的类名
	 * @param int	 $life_span		生命周期,超过此时间如果没有被 destroy() ,将被自动销毁。
	 * @return string				远程主机传回的 对象ID
	 */
	function create( $class_name, $parameters=array(), $end_time = 0 )
	{
		if( empty($end_time) )
			$end_time = __DEFAULT_ENDTIME ;

		$send_data = array(	'action'=>'create',
							'class_name'=>$class_name,
							'end_time'=>$end_time
						  );
		if( !empty($parameters) )
			$send_data['parameters'] = $parameters ;

		$this->ObjID
			= $this->_post_data( $send_data, true );

		return $this->ObjID ;
	}


	/**
	 * 销毁在远程主机 上创建的对象
	 *
	 * @param string $ObjID		对象id ,默认 为最近创建的对象
	 * @return bool
	 */
	function destroy( $ObjID=0 )
	{
		if( empty($ObjID) )
			$ObjID = $this->ObjID ;

		return $this->_post_data( array('action'=>'destroy','ObjID'=>$ObjID), true );
	}

	function get_attribute( $attribute_name, $ObjID=0 )
	{
		if( empty($ObjID) )
			$ObjID = $this->ObjID ;

		return $this->_post_data( array('action'=>'get_attribute','ObjID'=>$ObjID,'attribute_name'=>$attribute_name), true );
	}

	function set_attribute( $attribute_name, $attribute_value, $if_sync = true, $ObjID=0 )
	{
		if( empty($ObjID) )
			$ObjID = $this->ObjID ;

		$data = array(
				'action'=>'set_attribute',
				'ObjID'=>$ObjID,
				'attribute_name'=>$attribute_name,
				'attribute_value'=>$attribute_value
		) ;

		return $this->_post_data( $data, $if_sync );

	}

	function method_invoke( $func_name, $parameters=array(), $if_sync = true, $ObjID=0 )
	{
		if( empty($ObjID) )
			$ObjID = $this->ObjID ;

		$result = $this->_post_data( array('action'=>'method_invoke','ObjID'=>$ObjID,'func_name'=>$func_name,'parameters'=>$parameters), $if_sync );
		return $result ;
	}

	function output()
	{
		return $this->_response->get_body();
	}

	function _post_data( $data, $if_sync )
	{
		$this->waiting_response	 = $if_sync ;		// 通知 server 使用 同步/异步 工作
		$data['sync']			 = $if_sync ;		// 通知 client 使用 同步/异步 工作
		$data['client']			 = $this->cient ;	// 通知 server, client 的身份
		if( $this->readonly )
			$data['readonly']	 = '1' ;

		$data+= $this->additional ;
		$data = serialize_request_data($data) ;

		$this->send_http_body = $data;

		//pp($data);
		if( !$this->post( $this->soap_uri, $data, false, '', true ) )
													// 发送请求
			return false;

		$response = $this->_response->get_body() ;
		$this->recv_http_body = $response ;
		if( !preg_match( "/^(.*)\r\n\-{3} http soap server exception msg start -{3}\r\n(.*)\r\n-{3} http soap server response start -{3}\r\n(.*)$/s", $this->_response->get_body(), $re ) )
		{
			print $response ;
			return '' ;
		}
/*echo '{'.$response.'}';*/
		if(	trim($re[1])!=='' )						// 产生的输出
			print "{$re[1]}\r\n<br />\r\n" ;

		$re[2] = base64_decode($re[2]) ;
		$re[3] = base64_decode($re[3]) ;
		if( !empty($re[2]) )						// 接收消息
			$this->exception->load( $re[2] ) ;

		if( $o = @unserialize($re[3]) )				// 反序列化
			$re[3] = $o ;

		return $re[3];								// 返回回应,如果 $if_sync = false ,则返回为空
	}

	function out_exception_msg()
	{
		return $this->exception->out_msg() ;
	}
}


/**
 * SOAP 服务方,用于 相应协作来自其他主机,对本主机上的 php class 的 呼叫、调用
 *
 */
class http_soap_server extends base
{
	var $ObjID ;
	var $theObj ;

	var $readonly 		= false;
	var $exception ;
	
	function put_exception_msg( $msg )
	{
		if( empty($msg) )
			return false ;
		$this->exception->put( new msg($msg, 'Http Soap Server') ) ;
	}

	function http_soap_server()
	{
		$this->base( false );						// 初始化 基类,但不连接数据库

		global $http_soap_exception;
		if( is_object($http_soap_exception) )
			$this->exception = & $http_soap_exception ;

		$this->readonly = !empty($_REQUEST['readonly']) ;
			
		$this->theObj = & new http_soap_base();	
		$this->theObj->readonly = $this->readonly ;
		//$this->theObj->put_exception_msg('test msg');
	}
	
	function proc()
	{
		if( empty($_REQUEST['action']) )			// 检查 操作
		{
			$this->put_exception_msg( "No action parameter from client." );
			$this->_print( false );
			exit();
		}

		if( $_REQUEST['action'] == 'create' )		// 创建一个新的对象
		{
			if( empty( $_REQUEST['class_name'] ) )
			{
				$this->put_exception_msg( 'No class name.' );
				$this->_print( false );
				exit();
			}

			$this->_create() ;
		}
		else										// 对已有对象进行操作
		{
			$this->_load() ;						// 载入对象
			
			$action = '_'.$_REQUEST['action'];		// 执行操作
			$this->$action();				
		}

		$this-> theObj-> save();					// 保存对象
		exit();
	}

	/**
	 * 恢复对象,继续工作
	 *
	 */
	function _load()
	{
		if( empty($_REQUEST['ObjID']) )
		{
			$this->put_exception_msg( "No ObjID parameter from client." );
			$this->_print( false ) ;
			exit() ;
		}

		if( !$this->theObj->load( $_REQUEST['ObjID'] ) )
		{
			$this->put_exception_msg('Load Obj serialize file bad.') ;
			$this->_print(false);
			exit();
		}

		return true ;
		
	}

	/**
	 * 创建新的对象
	 *
	 */
	function _create()
	{
		if( $this->readonly )
		{
			$this->put_exception_msg('Can`t create new object by read-only client.') ;
			$this->_print( false ) ;
			return false ;
		}

		if( !isset($_REQUEST['parameters']) )
			$_REQUEST['parameters'] = array();

		if( !$this->theObj->create( $_REQUEST['class_name'], $_REQUEST['parameters'] ) )
		{
			$this->_print( false ) ;
			exit() ;
		}

		$this->ObjID = $this->theObj->ObjID ;
		$this->_print( $this->ObjID ) ;

		return true;
	}

	/**
	 * 销毁一个对象,当一件具体的工作完成后
	 *
	 */
	function _destroy()
	{
		
		if( $this->readonly )
		{
			$this->put_exception_msg('Can`t destroy object by read-only client.') ;
			$this->_print( false );
			exit();
		}

		$this->_print( $this->theObj->destroy() );
		exit();
	}

	/**
	 * 获得对象 的属性
	 *
	 */
	function _get_attribute()
	{
		if( empty($_REQUEST['attribute_name']) )
			return ;

		$attribute = $this->theObj->$_REQUEST['attribute_name'];
		$this->_print( $attribute );
		return ;
	}

	/**
	 * 设置对象的 属性
	 *
	 */
	function _set_attribute()
	{
		if( empty($_REQUEST['attribute_name']) )
		{				
			$this->put_exception_msg( "No 'attribute_name' from client." );
			$this->_print( false );
			exit();
		}

		$this->theObj->$_REQUEST['attribute_name'] = $_REQUEST['attribute_value'] ;
		$this->theObj->save() ;									// 保存

		$this->_print( true );
		return ;
	}

	/**
	 * 调用对象的方法
	 *
	 */
	function _method_invoke()
	{
		if( empty($_REQUEST['func_name']) )
		{
			$this->put_exception_msg( 'no func_name' ) ;
			$this->_print( false ) ;
			exit();
		}

		if( !method_exists ( $this->theObj, $_REQUEST['func_name'] ) )
		{
			$this->put_exception_msg( "No function {$_REQUEST['func_name']}()." ) ;
			$this->_print( false ) ;
			exit();
		}

		$return = $this->theObj->$_REQUEST['func_name']( isset($_REQUEST['parameters'])?$_REQUEST['parameters']:null );

		$this->_print( $return );
		return ;

	}

	function _serialize_array( $arr )
	{
		if( !is_array($arr) )
			return $arr ;

		if( empty($_REQUEST['client']) )
			$_REQUEST['client'] = 'php' ;

		if( in_array($_REQUEST['client'], array('python','js')) )
													// python 和 javascript 的序列化格式相同
		{
			$seria_str = '' ;
			foreach ($arr as $key=>$item)
			{
				if( $seria_str )
					$seria_str.= ',' ;
				if( is_array($item) )
					$seria_str.= "'{$key}':".$this->_serialize_array($item) ;
				else
				{
					$item = str_replace( "\r", '\r', $item ) ;
					$item = str_replace( "\n", '\n', $item ) ;
													// js client 中 eval 无法 反序列化 多行脚本
					$seria_str.= "'{$key}':\"$item\"" ;
				}
			}
			return "{{$seria_str}}" ;
		}
		elseif ( $_REQUEST['client'] == 'java' )	// java
		{
		}
		elseif ( $_REQUEST['client'] == 'vc++' )	// vc++
		{
		}
		elseif ( $_REQUEST['client'] == 'php' )		// php
			return serialize($arr) ;

	}

	function _print( $value )
	{
		$outStr = '' ;
		
		if( $_REQUEST['client'] == 'php' or empty($_REQUEST['client']) )
			$exception = serialize($this->exception) ;
		else
		{
			$exception = array() ;
			foreach ($this->exception->msgs as $theMsg)
				$exception[] = $theMsg->out() ;
			$exception = $this->_serialize_array( $exception ) ;
		}

		switch( 1 )
		{
			case is_array($value) or is_object($value) :
				$outStr = $this->_serialize_array($value);
				break ;

			case is_bool($value) :
				$outStr = (int) $value;
				break ;

			default :
				$outStr = (string) $value;
				break; 
		}

		$outStr = "\r\n--- http soap server exception msg start ---\r\n" . base64_encode($exception) . "\r\n--- http soap server response start ---\r\n" . base64_encode((string)$outStr) ;
		print $outStr ;
	}
	
	function destroy_endtime_obj()
	{
		if( ! $h = @opendir( $this->theObj->obj_serialize_dir ) )
		{
			$this->put_exception_msg('Destroy Obj: the obj_serialize_dir is not Exists') ;
			return false ;
		}

		$destroied = array() ;
		while( $filename = readdir($h) )
		{
			if( !preg_match( __OBJID_REGEXP, $filename, $re ) )
				continue ;

			include_once( $this->theObj->obj_serialize_dir . $filename ) ;
			if( $end_time < time() )
			{
				unlink( $this->theObj->obj_serialize_dir . $filename );
				$destroied [] = array( 'ObjID'=>$filename , 'class_name'=>$re[1], 'create_time'=>$re[2] ) ;
			}
		}

		return $destroied ;
	}
}

function get_Obj_info( $ObjID )
{
	if( !preg_match( __OBJID_REGEXP, $ObjID, $re ) )
		return false ;

	$info = array(
		'ObjID'			 => $ObjID ,
		'class_name'	 => $re[1] ,
		'create_time'	 => $re[2] ,
		'rand_seed'		 => $re[3]
	);

	return $info ;
}


if( !function_exists('serialize_request_data'))		// 如果在 workframe 中使用, 则此函数已在 base.class.php 中定义
{
	function serialize_request_data( $request, $val_name_pre='' )
	{
		$restr = array();//pp($request);sleep(10);
		foreach($request as $key=>$val)
		{
	/*		if( !empty($restr) )
				$restr.= '&';*/
			
			$val_name_pre ?	$key = "{$val_name_pre}%5B{$key}%5D" : null ;
	
			if( is_array($val) )
			{
				$return = serialize_request_data( $val, $key );
				if( empty($return) )
					continue ;
				$restr+= $return;
			}
			else
				$restr[$key]= $val;
		}
		
		return $restr;
	}
}
?>