PHP再学习5——RESTFul框架 远程控制LED

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 0.前言       去年(2013年)2月第一次接触yeelink平台,当时该平台已经运行了一些时间也吸引了不少极客。试想自己也将投身IoT(物联网)行业,就花了些时间研究了它。陆陆续续使用和研究了一年,大致围绕两个问题展开——1.yeelink平台如何使用,2.如何构造一个功能简单些的yeelink平台。

0.前言

 

    去年(2013年)2月第一次接触yeelink平台,当时该平台已经运行了一些时间也吸引了不少极客。试想自己也将投身IoT(物联网)行业,就花了些时间研究了它。陆陆续续使用和研究了一年,大致围绕两个问题展开——1.yeelink平台如何使用,2.如何构造一个功能简单些的yeelink平台。
    【 PHP学习笔记——索引博文
    本文将讨论如何构造一个简单restful架构平台(该平台有点像yeelink,不过功能比yeelink少的多),并结合树莓派实现LED的远程控制(网络控制)。构建一个RESTFul平台涉及到很多知识,通过以下链接提供一些学习资料。
    【1】 Slim——简单的 PHP5 框架可用来创建 RESTful 的 Web 应用
    【2】MySQL——关系型数据库管理系统
    【3】 RedBean——用 NoSQL 的语法来使用 ORM 框架
    【4】 JSON——轻量级的数据交换格式
    【5】 cURL——利用URL语法在命令行方式下工作的开源文件传输工具
 
    如果亲爱的读者想快速入门也可以看看我的博客文章。
    【1】Slim——【 PHP再学习4—— slim框架学习和使用
    【3】JSON——【 cJSON学习笔记
    【4】树莓派——【 树莓派学习笔记——yeelink 远程控制LED

    【2014年3月补充】    
    【1】如果您想获得本篇博文的源代码, 请点击这里CSDN代码仓库】。 数据库操作使用RedBean。
    【2】整理完本篇博文之后,修改了部分API函数并在GitHub建立了代码仓库(数据库操作并没有使用RedBean),如果本博文对您有用请点击这里GitHub Clone】。
     【3】如果想更深入一些例如部署到云平台中,请访问我的京东云擎——应用,相关代码仓库请猛击这里京东代码仓库
1.REST风格API
    在HTTP协议中定义了多种动作或者方法,这些方法具有不同的含义。
    【GET 获取】【POST 创建】【PUT 更新】【DELTE 删除】
    为了更好的理解以上的方法,下面结合LED远程控制举个例子。假设在数据库中已经保存了家庭中的LED设备信息,这些设备信息包括LED编号,LED设备描述和当前状态(打开或关闭)等,例如位于客厅的LED处于打开状态。
    可通过GET方法获得某个LED设备的信息或者全部LED的信息。这些LED灯具有一个唯一的编号,例如客厅的LED灯编号为1,那么 /leds/1就是编号为1的LED设备的唯一URI(可理解为网址)。通过这样类似的方法使每个LED设备具有网址,可通过该网址访问LED。通过GET方法可获得LED设备的所有信息,这些信息可通过JSON格式描述,例如:
    [{"id":1,"description":"raspberry pi IO1","status":"off"},{"id":2,"description":"raspberry pi IO2","status":"on"}]
 
    可通过POST方法创建一个新LED,新增加的LED具体信息可使用JSON格式描述,例如:
    {"description":"add a new led","status":"off"}
 
    可通过PUT方法更新LED信息,而具体内容用JSON格式描述,例如:
    {“status”:"on"}
 
    对于LED网络控制,REST API设计如下:
    GET /leds        返回所有的LED信息
    POST /leds      增加一个LED设备
    GET /leds/id    返回编号为id的LED设备信息
    PUT /leds/id    更新编号为id的LED设备信息

2.数据库准备
 
2.1 修改mysql密码
    【 PHP再学习4—— slim框架学习和使用】一文中推荐使用wampserver,该软件为集成安装包包括了PHP和MySQL,在使用mySQL之前最好修改默认密码,可参考博文【 修改mysql密码(博主:幸好我是程序猿)
    (2.1或2.2操作也可使用phpMyAdmin)
2.1 新建LED设备表
    使用mysql控制台,进入mysql数据库(输入use mysql,mysql为数据库的名称——安装wampserver后的一个默认数据库)。建立一个LED设备表,该表具有编号ID、描述description、状态status 字段,主键为id且自动增长(插入该数据表时 id写写入0或者不写,id编号会自动增长)。
[sql]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. CREATE TABLE IF NOT EXISTS `leds` (  
  2.   id int(11) NOT NULL AUTO_INCREMENT,  
  3.   description text NOT NULL,  
  4.   status text NOT NULL,  
  5.   PRIMARY KEY (id)  
  6. DEFAULT CHARSET=utf8;  
【小提示】
    【1】选择数据库           use <databs_name>;
    【2】查看表的结构        desc <table_name>;
    【3】删除表                 drop table <table_name>;
    【4】id的数据类型为int(11),千万别以为int的长度为11位,int(11)只是一种int的表达方式。
 
2.2 插入设备内容
    可在MySQL控制台输入以下内容,插入两条数据:
[sql]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. INSERT INTO leds (id, description , status) VALUES  (1, 'raspberry pi pcf8574-IO1','on');  
  2. INSERT INTO leds (id, description , status) VALUES  (2, 'raspberry pi pcf8574-IO2','off');  
3.GET方法获得所有LED信息
    使用GET方法或的所有LED状态——GET /leds。
    返回LED状态,使用JSON数据包描述。
    【代码片段】
[php]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. <?php  
  2.   
  3. require 'rb.php';  
  4. require 'Slim/Slim.php';  
  5.   
  6. \Slim\Slim::registerAutoloader();  
  7.   
  8. // 初始化数据库连接  
  9. R::setup('mysql:host=localhost;dbname=mysql','root','<your password>');  
  10. R::freeze(true);  
  11.   
  12. $app = new \Slim\Slim();  
  13.   
  14. // GET /leds  
  15. $app->get('/leds', function () use ($app) {   
  16.     // 查找所有设备  
  17.     $led_array = R::getAll('select * from leds');  
  18.     $app->response()->header('Content-Type', 'application/json');  
  19.     // 按照JSON格式输出  
  20.     echo json_encode( $led_array , JSON_NUMERIC_CHECK);  
  21. });  
  22.   
  23. $app->run();  
  24. ?>  
    【代码解释】
    【1】 require 'rb.php';  载入redbean,请把rb.php放在www根目录。
    【2】R::setup('mysql:host=localhost;dbname=mysql','root','<your password>');R::freeze(true);载入数据库,填入数据库的名称和密码。
    【3】$led_array = R::getAll('select * from leds'); 查询数据库获得LED数据包的所有内容,getAll返回一个索引数组。
    【4】 echo json_encode( $led_array , JSON_NUMERIC_CHECK); 请注意mysql的整形转到PHP时将变为string,如果没有JSON_NUMERIC_CHECK选项,那可能会获得{“id”:"1",....},这肯定不是你所愿意看到的。
    
    【简单测试】
    可通过浏览器,cURL工具,浏览器HTTP插件进行测试。
    
图1 使用浏览器获得所有LED信息
4. GET方法获得单个LED信息
    【代码片段】
[php]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. // GET /leds/:id  
  2. $app->get('/leds/:id', function ($id) use ($app) {      
  3.     try {  
  4.         // 查询数据库,只返回status状态  
  5.         $led_single = R::getRow('select status from leds where id = :id',array(':id'=>$id));  
  6.         if ($led_single) {  
  7.             $app->response()->header('Content-Type', 'application/json');  
  8.             // 按照JSON格式输出  
  9.             echo json_encode( $led_single, JSON_NUMERIC_CHECK);  
  10.         }   
  11.         else {  
  12.             $app->response()->status(404);  
  13.         }  
  14.     }   
  15.     catch (ResourceNotFoundException $e) {  
  16.         $app->response()->status(404);  
  17.     }   
  18.     catch (Exception $e) {  
  19.         $app->response()->status(400);  
  20.         $app->response()->header('X-Status-Reason', $e->getMessage());  
  21.     }  
  22. });  
    【代码解释】
    【1】$app->get('/leds/:id', function ($id) use ($app) id作为参数,可以输入数字1或2等。
    【2】$led_single = R::getRow('select status from leds where id = :id',array(':id'=>$id));
        select status from leds where id = :id 为SQL查询语句,和一般的SQL语句不同的是出现:id,array(':id'=>$id)该语句实现了SQL语句中的:id和输入参数id的绑定关系。在这里只查询status内容,其他内容忽略。
    【3】echo json_encode( $led_single, JSON_NUMERIC_CHECK); JSON格式输出,请主意使用JSON_NUMERIC_CHECK选项。
 
    【简单测试】
    使用curl工具测试,在windows 控制台中输入以下命令:
    
图2 使用cURL工具获得单个LED信息
 
5. PUT更新单个LED信息
    【代码片段】
[php]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. $app->put('/leds/:id', function ($id) use ($app) {      
  2.     try {  
  3.         // 获得HTTP请求中的JSON数据包  
  4.         $request = $app->request();  
  5.         $body = $request->getBody();  
  6.         $input = json_decode($body);   
  7.           
  8.         // 查找编号为ID的记录  
  9.         $led = R::findOne('leds', 'id=?', array($id));    
  10.           
  11.         // 重新修改status状态,并保存  
  12.         if ($led) {        
  13.             $led->status = (string)$input->status;  
  14.             R::store($led);      
  15.         } else {  
  16.             throw new ResourceNotFoundException();      
  17.         }  
  18.     } catch (ResourceNotFoundException $e) {  
  19.         $app->response()->status(404);  
  20.     } catch (Exception $e) {  
  21.         $app->response()->status(400);  
  22.         $app->response()->header('X-Status-Reason', $e->getMessage());  
  23.     }  
  24. });  
    【代码分析】
    【1】获得HTTP请求中的内容并进行解码,json_decode总是返回一个PHP对象而不是数组,所有后面对于input的操作需要使用->符号。
        $request = $app->request();
        $body = $request->getBody();
        $input = json_decode($body); 
    【2】$led = R::findOne('leds', 'id=?', array($id));  R::findOne总是返回一个对象,后面的操作需要使用->符号。
    【3】$led->status = (string)$input->status; 修改status。
    【4】R::store($led); 重新存储led信息。
 
    【简单测试】
    使用cURL工具测试,请求的内容为{"status":"off"},请求的方法为PUT。在windows控制台下输入以下命令:
    curl -i --request PUT  --data "{\"status\":\"on\"}"   http://localhost/leds/1
    注意:1)由于该HTTP负载并没有返回值,所有curl指令中加入-i选项,意为显示HTTP响应首部。
              2)PUT方法必须大写。    
图3 使用cURL更新单个LED状态
图4 编号为1的LED状态发生改变
 
6.树莓派 实现LED网络控制
    亲爱的朋友,如果您还不熟悉树莓派的话,可以参考:
    通过树莓派实现网络控制的方法也非常简单,树莓派不停的向服务器(在局域网中,IP为192.168.1.100)发送GET请求,服务器查询数据库以JSON格式返回LED信息,树莓派根据JSON数据包的内容控制LED灯,on为点亮,off为熄灭。
    【1】树莓派发送HTTP请求    GET /leds/1
    【2】服务器返回HTTP响应    {“status”:"off"}或{“status”:"on"}
    【3】树莓派根据status控制LED设备
 
    【代码片段】
[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. #!/usr/bin/env python  
  2. # -*- coding: utf-8 -*-  
  3. import requests  
  4. import smbus  
  5. import RPi.GPIO as GPIO  
  6. import time  
  7. # 打开 /dev/i2c-1  
  8. bus = smbus.SMBus(1)  
  9. # 设备URI  
  10. apiurl = 'http://192.168.1.100/leds/1'  
  11. while True:  
  12.   #发送请求  
  13.   r = requests.get(apiurl)  
  14.   # 打印内容  
  15.   print(r.text)  
  16.   # 响应转换内容为字典形式  
  17.   # 转换为字典类型 请注意 2.7.4版本使用r.json()  
  18.   led = r.json  
  19.   # {'value':'xx'} on打开状态,off关闭状态  
  20.   if led['status'] == 'on':  
  21.     print("led on")  
  22.     bus.write_byte( 0x20 , 1 )  
  23.   else:  
  24.     print("led off")  
  25.     bus.write_byte( 0x20 , 0 )  
  26.   # 延时5S  
  27.   time.sleep(5)  
 
    【代码测试】
    由于没有做前端,所有只能通过cURL指令改变LED的status。改变数据库中LED的status之后,树莓派上扩展板的真实LED状态便会发生变化。前端控制页面请期待后续博文。
图5 测试结果LED状态发生改变
 
7.其他遐想
    本文只是想阐述REST框架的创建和使用,树莓派的使用并不是本文的重点(树莓派让我扩展了知识面)。除了树莓派之外还可以使用其他设备“享用”这个REST服务,例如
    arduino平台——入门简单,加上ENC28J60可替代本文树莓派的功能。
    STM32平台——【 Yeelink平台使用——远程控制 RT Thread + LwIP+ STM32】简单修改该博客中的代码便可实现树莓派远程控制一样的功能,但是使用STM32平台需要更多的嵌入式方面的知识。
 

 

8.参考资料
【3】    yeelink API文档
 
9.关于我自己
    本人是一名嵌入式工程师,专注于物联网领域。虽然是一名嵌入式工程师,但是由于物联网的多领域交叉性,不得不让自己多学一些WEB方面的知识。对于工程师来说学习新的知识绝对是有必要的, 工程师没过过去只有去创造
    Email:xukai19871105@126.com
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
15天前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
31 4
|
24天前
|
SQL 关系型数据库 MySQL
如何学习PHP编程?
【10月更文挑战第2天】如何学习PHP编程?
37 9
|
25天前
|
SQL 安全 PHP
PHP 自发布以来一直在 Web 开发领域占据重要地位,PHP 8 更是带来了属性、刚性类型等新特性。
【10月更文挑战第1天】PHP 自问世以来,凭借其易用性和灵活性,在 Web 开发领域迅速崛起。从简单的网页脚本语言逐步演进为支持面向对象编程的现代语言,尤其自 PHP 5.3 引入命名空间后,代码组织和维护变得更加高效。PHP 7 的性能优化和 PHP 8 的新特性(如属性和刚性类型)进一步巩固了其地位。框架如 Laravel、Symfony、Yii2 和 CodeIgniter 等简化了开发流程,提高了效率和安全性。
38 2
|
2月前
|
JSON Go API
使用Go语言和Gin框架构建RESTful API:GET与POST请求示例
使用Go语言和Gin框架构建RESTful API:GET与POST请求示例
|
2月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
39 2
|
2月前
|
开发框架 JSON 缓存
震撼发布!Python Web开发框架下的RESTful API设计全攻略,让数据交互更自由!
在数字化浪潮推动下,RESTful API成为Web开发中不可或缺的部分。本文详细介绍了在Python环境下如何设计并实现高效、可扩展的RESTful API,涵盖框架选择、资源定义、HTTP方法应用及响应格式设计等内容,并提供了基于Flask的示例代码。此外,还讨论了版本控制、文档化、安全性和性能优化等最佳实践,帮助开发者实现更流畅的数据交互体验。
65 1
|
2月前
|
缓存 Java 应用服务中间件
随着微服务架构的兴起,Spring Boot凭借其快速开发和易部署的特点,成为构建RESTful API的首选框架
【9月更文挑战第6天】随着微服务架构的兴起,Spring Boot凭借其快速开发和易部署的特点,成为构建RESTful API的首选框架。Nginx作为高性能的HTTP反向代理服务器,常用于前端负载均衡,提升应用的可用性和响应速度。本文详细介绍如何通过合理配置实现Spring Boot与Nginx的高效协同工作,包括负载均衡策略、静态资源缓存、数据压缩传输及Spring Boot内部优化(如线程池配置、缓存策略等)。通过这些方法,开发者可以显著提升系统的整体性能,打造高性能、高可用的Web应用。
63 2
|
2月前
|
IDE 关系型数据库 PHP
php语言学习
【9月更文挑战第1天】php语言学习
32 3
|
2月前
|
SQL 安全 IDE
如何开始学习PHP?
【9月更文挑战第1天】如何开始学习PHP?
41 1
|
3月前
|
API 开发者 Python
"FastAPI路由大揭秘!轻松玩转URL映射,让你的Web应用路由设计既RESTful又灵活多变,秒杀传统框架的秘籍在这里!"
【8月更文挑战第31天】在Web开发中,路由是连接用户请求与后端逻辑的关键。FastAPI作为现代Python Web框架的佼佼者,以其简洁的API设计和高性能,提供了高度灵活的路由系统。本文通过开发一个博客系统的案例,详细介绍了FastAPI中路由的实现方法,包括基础路由定义、参数类型验证及路由分组与嵌套等,展示了如何轻松构建RESTful风格的URL映射,提升应用的可维护性和扩展性。
68 2