• PHP Cookbook读书笔记 – 第15章创建Web服务


    实现一个REST的WEB服务

    实现一个REST的web服务相对还是比较简单的,用到了HTTP的GET、POST、PUT、DELETE特性。其PHP的处理代码和普通处理POST和GET十分相似

    // 转换到大写
    $request_method = strtoupper($_SERVER['REQUEST_METHOD']);
    
    switch ($request_method) {
    case 'GET':
        $action = 'search';
        break;
    case 'POST':
        $action = 'add';
        break;
    case 'PUT':
        $action = 'update';
        break;
    case 'DELETE':
        $action = 'delete';
        break;
    default:
        // 无效的动作
        exit();
    }
    //处理完返回XML格式或Json等格式的结果

    这段代码就是对4种不同的请求进行处理,SQL与REST的对应关系可以看下表

    SQL REST
    CREATE POST
    SELECT GET
    UPDATE PUT
    DELETE DELETE
    对于需要授权的访问在rest中如何实现,书中并没有提及。现在很多开放API都是需要授权后才能使用的,它的实现原理是每次请求时需要携带一个额外的参数,这个参数就是经过加密的验证授权信息的。

    以SOAP方式提供数据

    使用ext/soap的SOAPServer类实现不带WSDL的WEB服务,你会发现SOAPServer来搭建WEB服务和写PHP的普通类差别并不大(当然也可以用函数),就是在实例化一个SOAPServer时将类名什么的与之关联,下面是一个简单的例子

    class pc_SOAP_return_time {
        public function return_time() {
            return date('Ymd\THis');
        }
    }
    
    $server = new SOAPServer(null, array('uri'=>'urn:pc_SOAP_return_time'));
    $server->setClass('pc_SOAP_return_time');
    $server->handle();

    客户端调用服务的代码如下:

    $opts = array('location' => 'http://api.example.org/getTime',
                  'uri' => 'urn:pc_SOAP_return_time');
    $client = new SOAPClient(null, $opts);
    $result = $client->__soapCall('return_time', array());
    print "The local time is $result.\n";

    用函数来处理的书中也有做介绍,因为我满脑子OO,就省略了。

    如果客户端调用一个服务端不存在的方法时,服务器会以一个SOAP故障作为应答,如果希望控制应答的内容,可以通过__call()方法来实现,如下面代码所示:

    class pc_SOAP_Process_All_Methods {
    
        // Handle any undefined methods here
        public function __call($name, $args) {
            // ...
        }
    }
    
    $server = new SOAPServer(null, array('uri'=>'urn:pc_SOAP_Process_All_Methods'));
    $server->setClass('pc_SOAP_Process_All_Methods');
    $server->handle();

    在SOAP方法中接受参数

    在服务端定义方法是增加参数,然后在客户端调用时SOAPClient->__soapCall('return_time', array(参数数组));是不是很简单,上面的代码各修改1处即可

    class pc_SOAP_return_time {
    //第一处不同,增加了$tz参数
        public function return_time($tz = '') {
            if ($tz) { $my_tz = date_default_timezone_set($tz); }
            $date = date('Ymd\THis');
            if ($tz) { date_default_timezone_set(ini_get('date.timezone')); }
            return $date;
        }
    }
    
    $server = new SOAPServer(null,array('uri'=>'urn:pc_SOAP_return_time'));
    $server->setClass('pc_SOAP_return_time');
    $server->handle();
    客户端调用
    $opts = array('location' => 'http://api.example.org/getTime',
                  'uri' => 'urn:pc_SOAP_return_time');
    $client = new SOAPClient(null, $opts);
    //第二处不同,将tz设置为奥斯陆
    $result = $client->__soapCall('return_time', array('tz' => 'Europe/Oslo'));
    print "The local time is $result.\n";

    自动生成WSDL文件

    前面已经说了,ext/soap扩展不支持WSDL自动生成功能,可以考虑手工生成WSDL文件(相信大家是不会这么做的),还有就是可以通过下面这几种非官方的脚本来实现,需要注意的是这几种方式都没能完全支持SOAP和WSDL规则,如果要很好的使用需要对它们进行仔细研究

    WSDL_Gen, by George Schlossnagle

    http://www.schlossnagle.org/~george/blog/index.php?/archives/234-WSDLGeneration.html

    wsdl-writer, by Katy Coe based on code by David Griffin

    http://www.djkaty.com/drupal/php-wsdl

    Web service helper, by David Kingma

    http://jool.nl/new/

    处理SOAP头部信息

    ext/soap发现一个带有SOAP头的客户端请求时,它首先会尝试调用一个具有相同名字的函数。调用完成后,会继续调用在SOAP主体中指定的函数。这样就可以使你基于SOAP头部数据来执行任何预请求的事务。

    但是,ext/soap服务器端不会以编程的方式对SOAP头部和主体进行真正的区分。当ext/soap发现一个SOAP头时,它会在处理主体之前尝试调用与该头部元素同名的方法。

    如果SOAP客户端指定的头部不存在,ext/soap会跳过该方法直接转到主体中。如果头部中的mustUnderstand 属性标记为true,那么SOAPServer就会放出一个SOAP故障。

    $opts = array('location' => 'http://api.example.org/getTime',
                  'uri' => 'urn:pc_SOAP_return_time');
    $client = new SOAPClient(null, $opts);
    $set_timezone = new SOAPVar('Europe/Oslo', XSD_STRING);
    
    //设置SOAP头部
    $tz = new SOAPHeader('urn:pc_SOAP_return_time', 'set_timezone', $set_timezone);
    
    $result = $client->__soapCall('return_time', array(), array(), array($tz));
    print "The local time is $result.\n";

    生成SOAP头信息

    class pc_SOAP_return_time {
        public function return_time() {
            $tz = date_default_timezone_get();
    
            //生成头部信息
            $header = new SoapHeader('urn:pc_SOAP_return_time', 'get_timezone', $tz);
    
            $GLOBALS['server']->addSoapHeader($header);
            return date('Ymd\THis');
        }
    }
    $server = new SOAPServer(null, array('uri'=>'urn:pc_SOAP_return_time'));
    $server->setClass('pc_SOAP_return_time');
    $server->handle();

    由于在方法的作用域中不能轻易地访问到$server对象,需要通过$GLOBALS数组来访问该对象。响应时会包含下面的SOAP头:

    
    America/Los Angeles
    

    用SOAP头实现验证

    因为没有办法强制ext/soap请求SOAP头部信息,所以需要在每个需要验证的方法内添加一个判断语句对pc_authenticate_user进行判断,如果客户端没有通过验证则抛出一个SOAP故障

    function pc_authenticate_user($username, password) {
        // authenticate user
        $is_valid = true; // Implement your lookup here
    
        if ($is_valid) {
            return true;
        } else {
            return false;
        }
    }
    
    
    class pc_SOAP_return_time {
        private $authenticated;
    
        public function __construct() {
            $this->authenticated = false;
        }
    
        public function authenticate_user($args) {
            // Throw SOAP fault for invalid username and password combo
            if (! pc_authenticate_user($args->username,
                                       $args->password)) {
    
                throw new SOAPFault("Incorrect username and password combination.", 401);
            }
    
            $this->authenticated = true;
        }
    
        // Rest of SOAP Server methods here...
        public function soap_method() {
            if ($this->authenticated) {
                // Method body here...
            } else {
                throw new SOAPFault("Must pass authenticate_user Header.", 401);
            }
        }
    
    }
    
    $server = new SOAPServer(null, array('uri'=>'urn:pc_SOAP_return_time'));
    $server->setClass('pc_SOAP_return_time');
    
    $server->handle();
    下面是客户端调用的代码
    $opts = array('location' => 'http://api.example.org/getTime',
                  'uri' => 'urn:pc_SOAP_return_time');
    $client = new SOAPClient(null, $opts);
    class SOAPAuth {
        public $username;
        public $password;
        public function __construct($username, $password) {
            $this->username = $username;
            $this->password = $password;
        }
    }
    
    $auth = new SOAPAuth('elvis', 'the-king');
    $header = new SOAPHeader('urn:example.org/auth', 'authenticate_user', $auth);
    $result = $client->__soapCall('return_time', array(), array(), array($header));
  • 相关阅读:
    Vue动画操作
    js this
    flask 操作mysql的两种方式-sqlalchemy操作
    flask 操作mysql的两种方式-sql操作
    ansible批量加用户
    使用 WTForms 进行表单验证的例子
    flask开发用户管理系统wtf版
    [转]Python格式化输出
    scrapy中response.body 与 response.text区别
    flask开发表单
  • 原文地址:https://www.cnblogs.com/Excellent/p/2258793.html
Copyright © 2020-2023  润新知