ibm bluemix 教程关于php扩展的问题

IBM Bluemix
点击按钮,开始云上的开发!
developerWorks 社区
了解共享内存,学习如何在 Web 应用程序中将共享内存用作一种数据存储选项,并享受它的高速、可靠性和与其他应用程序交换数据的优势。提供的示例展示了它如何帮助解决 Web 应用程序开发中的常见问题。
, 软件工程师和讲师, 4Linux
Klaus Silveira 是一位专门研究 PHP 的软件工程师和讲师,对开发用于 Web 的智能解决方案和通过 SimpleString 和 SimpleSHM 等项目为开源领域做贡献充满激情。他在 4Linux 工作,这是一家致力于开发免费软件解决方案的巴西公司。他负责开发企业 Web 应用程序和 PHP 课程,帮助开发人员为 Zend PHP 认证考试做准备。
概述共享内存是一种在相同机器中的应用程序之间交换数据的有效方式。一个进程可创建一个可供其他进程访问的内存段,只要它分配了正确的权限。每个内存段拥有一个惟一的 ID(称为 shmid),这个 ID 指向一个物理内存区域,其他进程可在该区域操作它。创建并提供了合适的权限之后,同一台机器中的其他进程就可以操作这些内存段:读取、写入和删除。这表明使用 C 语言编写的应用程序可与使用其他语言(比如 Java™ 或 PHP)编写的应用程序共享信息。它们都可以共享信息,只要它们可访问和理解该信息。共享内存在针对大部分语言的实现中得到了广泛使用,所以访问应该不是问题。要理解信息,我们可以使用一种标准格式,比如 XML 或 JSON。共享内存的使用是一种在进程之间交换数据的快速方法,主要因为在创建内存段之后传递数据,不会涉及内核。这种方法常常称为进程间通信 (IPC)。其他 IPC 方法包括管道、消息队列、RPC 和套接字。当使用需要彼此通信的应用程序的生态系统时,这种在应用程序之间快速、可靠地交换数据的能力非常有用。取决于生态系统的大小,使用数据库在应用程序之间交换信息的常用方法常常会导致查询缓慢,甚至 I/O 阻塞。使用共享内存,没有 I/O 会减缓开发人员的进度。本文的提议非常简单,学习如何使用 PHP 创建和操作共享内存段,使用它们存储可供其他应用程序使用的数据集。即使没有使用共享内存交换数据的计划,它本身也在许多好处,因为它使应用程序能够远离 I/O 问题。将数据集直接存储在内存中具有诸多优势,从 Web 服务数据缓存到会话共享。它是一个非常有用的概念,每个 PHP 开发人员都应该知道。共享内存和 PHPPHP 拥有丰富的可用扩展,共享内存也一样。使用一些共享的函数,无需安装任何扩展,开发人员就能够轻松操作内存段。创建内存段共享内存函数类似于文件操作函数,但无需处理一个流,您将处理一个共享内存访问 ID。第一个示例就是 shmop_open 函数,它允许您打开一个现有的内存段或创建一个新内存段。此函数非常类似于经典的 fopen 函数,后者打开用于文件操作的流,返回一个资源供其他希望读取或写入该打开的流的函数使用。让我们看看清单 1 中的 shmop_open。清单 1. shmop_open 函数&?php
$systemid = 864; // System ID for the shared memory segment
$mode = "c"; // Access mode
$permissions = 0755; // Permissions for the shared memory segment
$size = 1024; // Size, in bytes, of the segment
$shmid = shmop_open($systemid, $mode, $permissions, $size);
?&该函数中出现的第一个事物是系统 ID 参数。这是标识系统中的共享内存段的数字。第二个参数是访问模式,它非常类似于 fopen 函数的访问模式。您可以在 4 种不同的模式下访问一个内存段:模式 “a”,它允许您访问只读内存段模式 “w”,它允许您访问可读写的内存段模式 “c”,它创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写模式 “n”,它创建一个新内存段,如果该内存段已存在,则会失败第三个参数是内存段的权限。您必须在这里提供一个八进制值。第四个参数提供内存段大小,以字节为单位。在写入一个内存段之前,您必须在它之上分配适当的字节数。请注意,此函数返回一个 ID 编号,其他函数可使用该 ID 编号操作该共享内存段。这个 ID 是共享内存访问 ID,与系统 ID 不同,它以参数的形式传递。请注意不要混淆这两者。如果失败,shmop_open 将返回 FALSE。向内存段写入数据使用 shmop_write 函数向共享内存块写入数据。此函数的使用很简单,它仅接受 3 个参数,如清单 2 所示。清单 2. 使用 shmop_write 向共享内存块写入数据&?php
$shmid = shmop_open(864, 'c', );
shmop_write($shmid, "Hello World!", 0);
?&这个函数类似于 fwrite 函数,后者有两个参数:打开的流资源(由 fopen 返回)和您希望写入的数据。shmop_write 函数也执行此任务。第一个参数是 shmop_open 返回的 ID,它识别您操作的共享内存块。第二个参数是您希望存储的数据,最后的第三个参数是您希望开始写入的位置。默认情况下,我们始终使用 0 来表示开始写入的位置。请注意,此函数在失败时会返回 FALSE,在成功时会返回写入的字节数。从内存段读取数据从共享内存段读取数据很简单。您只需要一个打开的内存段和 shmop_read 函数。此函数接受一些参数,工作原理类似于 fread。参见清单 3,读取一个 PHP 文件的内容。清单 3. 使用 shmop_read 读取一个文件的内容&?php
$stream = fopen('file.txt', 'r+');
fwrite($stream, "Hello World!");
echo fread($stream, 11);
?&读取共享内存段的内容的过程与此类似,如清单 4 所示:清单 4. 读取共享内存段的内容&?php
$shmid = shmop_open(864, 'c', );
shmop_write($shmid, "Hello World!", 0);
echo shmop_read($shmid, 0, 11);
?&请留意这里的参数。shmop_read 函数将接受 shmop_open 返回的 ID,我们已知道它,不过它还接受另外两个参数。第二个参数是您希望从内存段读取的位置,而第三个是您希望读取的字节数。第二个参数可以始终为 0,表示数据的开头,但第三个参数可能存在问题,因为我们不知道我们希望读取多少字节。这非常类似于我们在 fread 函数中的行为,该函数接受两个参数:打开的流资源(由 fopen 返回)和您希望从该流读取的字节数。使用 filesize 函数(它返回一个文件中的字节数)来完整地读取它。幸运的是,当使用共享内存段时,shmop_size 函数返回一个内存段的大小(以字节为单位),类似于 filesize 函数。参见清单 5。 清单 5. shmop_size 函数返回内存段大小,以字节为单位&?php
$shmid = shmop_open(864, 'c', );
shmop_write($shmid, "Hello World!", 0);
$size = shmop_size($shmid);
echo shmop_read($shmid, 0, $size);
?&删除内存段我们学习了如何打开、写入和读取共享内存段。要完成我们的 CRUD 类,我们还需要学习如何删除内存段。该任务可使用 shmop_delete 函数轻松完成,该函数仅接受一个参数:我们希望删除的共享内存 ID。清单 6. shmop_delete 标记要删除的内存段&?php
$shmid = shmop_open(864, 'c', );
shmop_write($shmid, "Hello World!", 0);
shmop_delete($shmid);
?&这不会实际删除该内存段。它将该内存段标记为删除,因为共享内存段在有其他进程正在使用它时无法被删除。shmop_delete 函数将该内存段标记为删除,阻止任何其他进程打开它。要删除它,我们需要关闭该内存段。关闭内存段打开一个共享内存段会 “附加” 到它。附加该内存段之后,我们可在其中进行读取和写入,但完成操作后,我们必须从它解除。这使用清单 7 中的 shmop_close 函数来完成。这非常类似于处理文件时的 fclose 函数。打开包含一个文件的流并在其中读取或写入数据后,我们必须关闭它,否则将发生锁定。清单 7. 使用 shmop_close 与一个内存段分开&?php
$shmid = shmop_open(864, 'c', );
shmop_write($shmid, "Hello World!", 0);
shmop_delete($shmid);
shmop_close($shmid);
?&使用共享内存作为一个存储选项有了共享内存和共享内存段上基本 CRUD 操作的基本知识,是时候应用此知识了。我们可以使用共享内存作为一种独特的存储选项,提供快速读/写操作和进程互操作性等优势。对于 Web 应用程序,这意味着:缓存存储(数据库查询、Web 服务数据、外部数据)会话存储应用程序之间的数据交换在继续之前,我想介绍一个名为 SimpleSHM 小型库。SimpleSHM 是一个较小的抽象层,用于使用 PHP 操作共享内存,支持以一种面向对象的方式轻松操作内存段。在编写使用共享内存进行存储的小型应用程序时,这个库可帮助创建非常简洁的代码。要了解 SimpleSHM,请访问 。您可以使用 3 个方法进行处理:读、写和删除。从该类中简单地实例化一个对象,可以控制打开的共享内存段。清单 8 展示了基本用途。清单 8. SimpleSHM 基本用途&?php
$memory = new SimpleSHM;
$memory-&write('Sample');
echo $memory-&read();
?&请注意,这里没有为该类传递一个 ID。如果没有传递 ID,它将随机选择一个编号并打开该编号的新内存段。我们可以以参数的形式传递一个编号,供构造函数打开现有的内存段,或者创建一个具有特定 ID 的内存段,如清单 9 所示。清单 9. 打开一个特定的内存段&?php
$new = new SimpleSHM(897);
$new-&write('Sample');
echo $new-&read();
?&神奇的方法 __destructor 负责在该内存段上调用 shmop_close 来取消设置对象,以与该内存段分离。我们将这称为 “SimpleSHM 101”。现在让我们将此方法用于更高级的用途:使用共享内存作为存储。存储数据集需要序列化,因为数组或对象无法存储在内存中。尽管这里使用了 JSON 来序列化,但任何其他方法(比如 XML 或内置的 PHP 序列化功能)也已足够。清单 10 给出了一个示例。清单 10. 使用共享内存作为存储&?php
require('SimpleSHM.class.php');
$results = array(
'user' =& 'John',
'password' =& '123456',
'posts' =& array('My name is John', 'My name is not John')
$data = json_encode($results);
$memory = new SimpleSHM;
$memory-&write($data);
$storedarray = json_decode($memory-&read());
print_r($storedarray);
?&我们成功地将一个数组序列化为一个 JSON 字符串,将它存储在共享内存块中,从中读取数据,去序列化 JSON 字符串,并显示存储的数组。这看起来很简单,但请想象一下这个代码片段带来的可能性。您可以使用它存储 Web 服务请求、数据库查询或者甚至模板引擎缓存的结果。在内存中读取和写入将带来比在磁盘中读取和写入更高的性能。使用此存储技术不仅对缓存有用,也对应用程序之间的数据交换也有用,只要数据以两端都可读的格式存储。不要低估共享内存在 Web 应用程序中的力量。可采用许多不同的方式来巧妙地实现这种存储,惟一的限制是开发人员的创造力和技能。结束语本文介绍了用于操作共享内存段的 PHP 工具包中的大部分工具,解释了共享内存的工作原理。此外,还提供了改进 Web 应用程序的建议,列出了在为 Web 应用程序问题创建解决方案时要考虑的一些因素。这些概念和实现指南可帮助您建立一个起点。我们构建的早期模型可帮助您构想更复杂的特性和解决方案。未来计划我们列出了共享内存中最可能实现的一些常见问题,比如缓存、会话共享和应用程序之间的常见数据交换。此篇共享内存简介为您就常见问题而探索更佳解决方案提供机会。您可以自由扩展当前的 SimpleSHM 实现,以匹配您的需要和将更改贡献给该项目。
参考资料 Michael Kerrisk 撰写的
一书非常好地介绍了进程间的通信,其中第 45 到 48 章专门介绍了 System V IPC。Dave Marshall 的 “” 文章介绍了在 C 语言中使用共享内存函数的一种有趣且实用的方法。Richard Stevens 的
提供了优秀的技术内容和多个 C 语言实现。请查阅 。查阅 IBM developerWorks 的 ,扩展您的 PHP 技能。阅读其他与
相关的 developerWorks 文章和教程。随时关注 developerWorks 和。
访问 developerWorks 获得丰富的 how-to 信息、工具和项目更新以及,帮助您用开放源码技术进行开发,并将它们与 IBM 产品结合使用。使用
创新您的下一个开源开发项目,可以下载获取。。加入 ,developerWorks 社区是一个面向全球 IT 专业人员,可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。加入 ,参与在线交流。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
为灾难恢复构建应用,赢取现金大奖。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Open sourceArticleID=800478ArticleTitle=使用 PHP 直接在共享内存中存储数据集publish-date=IBM Bluemix
点击按钮,开始云上的开发!
developerWorks 社区
REST API 越来越受与库无关的数据访问和操作的欢迎,因为它们易于理解,可以快速编码,并且可以通过内置 HTTP 支持在所有编程语言中使用。本文展示了在 Bluemix 上如何使用 PHP 和 MySQL 构建并立即部署 REST API。本文使用 Bullet 微型框架和 Eloquent ORM 以及 PHP Cloud Foundry 构建包和绑定的 MySQL 服务实例来实现 API。
, Melonfire 的创始人兼 CEO, Melonfire
vikram-vaswani.in
简介如果您正在构建与在线产品或服务交互的应用程序,那么很可能您正在使用 REST API 提取数据或推入数据。在过去几年里,REST API 越来越受欢迎,因为它们易于理解,可以快速编码,并且可以通过内置 HTTP 支持在所有编程语言中使用。如果您正在开发自己的云服务,那么 REST API 是一种促进数据共享和重用的出色方式。如果允许外部开发人员通过 REST 访问您的数据,他们就可以轻松地构建酷炫的新应用程序,并以一些有趣的方式利用您的产品或数据。考虑一下围绕 Facebook、Twitter 或 Instagram 开发的应用程序生态系统,好处显而易见。“ “如果允许外部开发人员通过 REST 访问您的数据,他们就可以轻松地构建酷炫的新应用程序,并以一些有趣的方式利用您的产品或数据。””本文提供了一个速成课程,介绍了如何使用 PHP 微型框架 Bullet 创建 REST API。除了解释如何实现 4 种基本的 REST 方法之外,本文还介绍了如何为常见的功能(比如 API 身份验证和多种数据格式支持)添加支持,然后将 API 部署到 Bluemix。来吧,让我们开始吧!了解 REST API 基础知识首先,我们需要花费几分钟时间了解一下 REST,即 Representational State Transfer(具象状态传输)。REST 是一种基于 “资源” 和 “操作” 的 API 开发风格。资源是引用想要执行操作的对象或实体的 URL(例如,/users 或 /photos),而操作是 4 个 HTTP 动词之一:GET(检索)POST(创建)PUT (更新)DELETE(删除)下面的示例明确说明了这一点。假设您有一个专为跟踪软件缺陷设计的应用程序,而且您想轻松地重用和操作应用程序数据库中的数据。您已经显示了一个 URL 端点(将其称为 /bugs),并允许外部开发人员使用不同的 HTTP 方法和内容访问此端点(例如,使用 GET /bugs 列出所有缺陷,或者是使用 DELETE /bugs/78 删除编号为 78 的缺陷)。基于 HTTP 方法和内容,可以推导出正在请求的操作,并对数据采取相应的操作。下面是一些示例:GET /documents:检索一个文档列表。GET /bugs/123:检索编号为 123 的缺陷。POST /photos:使用 POST 请求正文创建一个新照片。PUT /photos/123:使用 PUT 请求正文更新编号为 123 的照片。DELETE /orders/123:删除编号为 123 的订单。您需要的内容本文中开发的示例 REST API 假设一个产品数据库,并侧重于使用常规 REST 协定支持您检索、添加、删除和更新这些产品。为简单起见,Product 资源仅有三个属性:惟一的标识符、名称和价格。我还进一步假设产品数据保存在一个 MySQL 数据库中,并且 API 请求和响应是使用 JSON 编码的(尽管在后面的部分中,我还介绍了使用 XML 作为一种替代方法)。下面是您需要的内容:基本熟悉 、 和
或 一个本地 PHP/MySQL 开发环境或一个 Bluemix 帐户,PHP 依赖关系管理器(仅在 Bluemix 部署时才需要)一个文本编辑器或 IDE步骤 1:设置应用程序数据库使用下列 MySQL 表定义和示例数据设置应用程序数据库。如果您只在本地进行开发和部署,那么可以使用这种方法针对要连接的 API 初始化 MySQL 数据库表。如果在 Bluemix 上进行部署,那么暂时可以跳过这一步;完成了步骤 7 在 Bluemix 上初始化和绑定 MySQL 服务实例后,再返回到这一步。CREATE TABLE IF NOT EXISTS `products` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`price` decimal(5,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_
INSERT INTO `products` (`id`, `name`, `price`) VALUES
(1, 'Garden spade', 15.99),
(2, 'Cotton hammock', 54.50),
(3, 'Single airbed', 35.49);步骤 2:安装 Bullet 和 Eloquent下一步是下载并设置
微型框架。为什么要使用 Bullet 呢?因为它包含一个灵活的 URL 路由器,可以轻松地在自定义 URL 上创建和响应不同的 HTTP 方法,它还包含一个嵌套路由回调,可以简化常见重复任务(比如 API 身份验证)的执行。为了简化数据库访问,我将使用 ,这是一个受欢迎的对象关系映射器(Object Relational Mapper,ORM),它使用 ActiveRecord 实现来简化数据库记录的使用。Eloquent 是 Laravel PHP 框架的一部分,但它也可以单独使用。我将使用 Composer(PHP 依赖关系管理器)来下载和设置 Bullet 与 Eloquent。下面是 Composer 配置文件,可以将它保存到 $APP_ROOT/composer.json。在本文中,$APP_ROOT 指应用程序工作目录。{
"require": {
"vlucas/bulletphp": "*",
"illuminate/database": "*"
}现在,可以使用 Composer 的下列命令安装 Bullet 和 Eloquent:shell& php composer.phar install为了简化应用程序访问,还可以在开发环境中定义新的虚拟主机,并将其文档根目录指定为 $APP_ROOT。尽管此步骤是可选的,但建议使用它,因为它在 Bluemix 上创建了一个更接近目标部署环境的副本。要在 Apache 中为应用程序设置一个命名的虚拟主机,请打开 Apache 配置文件(httpd.conf 或 httpd-vhosts.conf)并添加下列行。 NameVirtualHost 127.0.0.1
&VirtualHost 127.0.0.1&
DocumentRoot "/usr/local/apache/htdocs/api"
ServerName api.localhost
&/VirtualHost&要在 nginx 中为应用程序设置一个命名的虚拟主机,请打开 nginx 配置文件 (nginx.conf) 并添加下列行。 server {
server_name api.
root /usr/local/apache/htdocs/
try_files $uri /index.
location ~ \.php$ {
try_files $uri =404;
include fastcgi_
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_
# assumes you are using php-fcgi
fastcgi_pass 127.0.0.1:90;
}这些行定义一个新的虚拟主机,http://api.localhost/,它的文档根目录对应于 $APP_ROOT 目录(记住更新此目录以反映您自己的本地设置)。重启 Web 服务器以激活这些新的设置。请注意,您可能需要更新网络的本地 DNS 服务器,让它知道新的主机。步骤 3:处理资源集合的 GET 请求Bullet 每次解析一个 URL 段并使用回调响应特定的路径或参数模式。可以在每个 HTTP 方法上定义回调,这允许您对 GET 请求而不是 POST 请求执行不同的操作。典型的 REST API 支持两种 GET 请求:第一种请求针对资源集合 (GET /products) ,而第二种请求针对具体资源 (GET /products/123)。首先编写代码来处理第一种场景:使用数据库的所有可用产品列表响应 GET /products 请求。使用下列代码更新 $APP_ROOT/index.php 文件。&?php
// set up Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// initialize application
$app = new Bullet\App();
$app-&path('v1', function($request) use ($app) {
$app-&path('products', function($request) use ($app) {
// GET /v1/products
// list all products
$app-&get(function() use ($app)
$products = Product::all();
return $products-&toArray();
echo $app-&run(new Bullet\Request());第一步是初始化 Composer 自动加载器,它负责根据需要加载所需的类。然后,创建一个新的 Bullet\App 对象来表示应用程序,并使用此应用程序对象的 path() 方法来设置端点 /v1/products 的嵌套 URL 路径。最里面的 path() 回调定义此端点支持的方法 — 在本例中,使用应用程序对象的 get() 方法来定义 GET 请求的处理程序。路由处理程序使用 Eloquent 模型返回数据库的所有产品。由于此处理程序返回的是一个数组,因此 Bullet 自动假设响应格式应该是 JSON,使用 'Content-Type: application/json' 标头和 200 OK 成功代码来转换此数组,并将它发送回客户端。如果有任何错误,异常处理程序会捕捉错误,并使用 500 Internal Server Error 和一个包含错误消息的 JSON 正文将错误返回给客户端。当收到传入请求时,通过执行 Bullet 应用程序,应用程序对象的 run() 方法(如上一个清单的最后一行所示)将所有内容聚集在一起。此时,您可能会认为这一切都是有意义的,除了一个问题:此 Eloquent 模型来自何处?下一个清单会将会说明这一点,使用 GET 处理程序添加使用 Eloquent 所需的代码,如上所述。&?php
// set up Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// use Eloquent ORM
use Illuminate\Database\Capsule\Manager as C
use Illuminate\Database\Schema\Blueprint as S
// create model for Eloquent ORM mapped to REST API resource
class Product extends Illuminate\Database\Eloquent\Model {
public $timestamps =
// get MySQL service configuration from Bluemix
$services = getenv("VCAP_SERVICES");
$services_json = json_decode($services, true);
$mysql_config = $services_json["mysql-5.5"][0]["credentials"];
$db = $mysql_config["name"];
$host = $mysql_config["host"];
$port = $mysql_config["port"];
$username = $mysql_config["user"];
$password = $mysql_config["password"];
// initialize Eloquent ORM
$capsule = new C
$capsule-&addConnection(array(
=& 'mysql',
'database'
'username'
=& $username,
'password'
=& $password,
=& 'utf8',
'collation' =& 'utf8_unicode_ci',
$capsule-&setAsGlobal();
$capsule-&bootEloquent();
// initialize application
$app = new Bullet\App();
$app-&path('v1', function($request) use ($app) {
$app-&path('products', function($request) use ($app) {
// GET /v1/products
// list all products
$app-&get(function() use ($app)
$products = Product::all();
return $products-&toArray();
echo $app-&run(new Bullet\Request());Eloquent 随附提供了一个 Capsule 管理器实例,旨在简化 Laravel 外部的 Eloquent 使用。上一个清单演示了实际的 Capsule 实例,建立了一个到 MySQL 数据库的新连接,并使 Capsule 实例在全局可用。由于本文的最终目的是将应用程序部署到 Bluemix,因此会从特殊的 Bluemix VCAP_SERVICES 环境变量提取 MySQL 连接的凭据;但是,如果您打算在本地进行部署,那么可以使用特定于本地数据库服务器的值取代这些值。您还会注意到扩展 Illuminate\Database\Eloquent\Model 类的 Product 模型。此 Product 模型提供了许多预定义的方法,可以简化相应数据库记录的使用。您已经看到了其中的一个实际方法 —Product::all()—,它负责在内部生成对 "return all products in the database" 的 SELECT 查询。下面是成功的 /v1/products GET 请求的结果。步骤 4:处理新资源的 POST 请求可以类似的方式处理 POST 请求并将它们转换为新产品记录。&?php
// set up Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// initialize Eloquent ORM and model
// snipped
// initialize application
$app = new Bullet\App();
$app-&path('v1', function($request) use ($app) {
$app-&path('products', function($request) use ($app) {
// POST /v1/products
// create new product
$app-&post(function($request) use ($app) {
$product = new Product();
$product-&name = trim(htmlentities($request-&name));
$product-&price = round(trim(htmlentities($request-&price)), 2);
if ($product-&name && $product-&price) {
$product-&save();
return $app-&response(201, $product-&toArray());
return 400;
echo $app-&run(new Bullet\Request());此清单为 /v1/products 的 POST 请求添加了一个新处理程序。当应用程序收到 POST 请求时,会创建一个空白的 Product 对象,根据请求对象设置 Product 'name' 和 'price',并调用模型的 save() 对象来为数据库添加新记录。如果成功添加了记录,那么处理程序将会返回 201 Created 状态代码和新 Product 资源的 JSON 表示形式。如果没有成功,则会返回 400 Bad Request 或 500 Internal Server Error 错误代码和一条解释错误的 JSON 消息。在下面查看成功和失败的 POST 请求和响应示例。值得注意的一个有趣现象是:在 POST 正文内容中,已创建的新 Product 资源被作为 JSON 对象传递给 API。但是,在 POST 处理程序中,您会看到没有使用 PHP 的 json_decode() 函数来解码 POST 有效负载。这是因为在 POST 或 PUT 请求中遇到 JSON 有效负载时 Bullet 会自动进行解码。然后,可以直接使用 JSON 对象属性作为请求对象的属性。步骤 5:处理各个资源的 GET、PUT 和 DELETE 请求在上一部分中,我介绍了如何处理资源集合的 GET 请求 (GET /v1/products)。但是,REST API 应该还支持使用惟一资源标识符直接访问资源(GET /v1/products/123 或 DELETE /v1/products/123)。这使得可以使用 API 检索、更新或删除各个资源。与之前看到的 path() 方法(针对静态 URL 路径)类似,Bullet 还包含一种 param() 方法,它旨在处理包含变量的 URL 路径。下列清单在具体资源的 GET 请求处理程序上下文中演示了这一方法。&?php
// set up Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// initialize Eloquent ORM and model
// snipped
// initialize application
$app = new Bullet\App();
$app-&path('v1', function($request) use ($app) {
$app-&path('products', function($request) use ($app) {
$app-&param('int', function($request, $id) use($app) {
$product = Product::find($id);
if(!$product) {
return 404;
// GET /v1/products/:id
// list single product by id
$app-&get(function($request) use($product, $app) {
return $product-&toArray();
echo $app-&run(new Bullet\Request());此清单以 /v1/products/[id] 的形式设置了 URL 的回调处理程序,其中 [id] 是一个变量路径段,表示惟一资源标识符。'int' 参数进一步指定了此变量是一个分配给 $id 变量的整数。在此清单中,从 URL 路径捕获的资源标识符被传递给了 Product 模型,并且此模型的 find() 方法用于返回相应的数据库记录。然后,Bullet 将记录转换为 JSON 格式并将它返回给客户端。如果没有找到匹配的记录,处理程序会返回 404 Not Found 错误代码。如果存在错误,则异常处理程序会捕获错误并将它传递回 500 Internal Server Error 错误代码。下面是成功的 GET 请求和响应的结果。有了此结构,针对具体资源添加 DELETE 和 PUT 请求的支持就会非常简单。查看下列清单,此清单包含了此额外功能。&?php
// set up Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// initialize Eloquent ORM and model
// snipped
// initialize application
$app = new Bullet\App();
$app-&path('v1', function($request) use ($app) {
$app-&path('products', function($request) use ($app) {
$app-&param('int', function($request, $id) use($app) {
$product = Product::find($id);
if(!$product) {
return 404;
// GET /v1/products/:id
// list single product by id
$app-&get(function($request) use($product, $app) {
return $product-&toArray();
// PUT /v1/products/:id
// update product by id
$app-&put(function($request) use($product, $app) {
$product-&name = trim(htmlentities($request-&name));
$product-&price = round(trim(htmlentities($request-&price)), 2);
if ($product-&name && $product-&price) {
$product-&save();
return $app-&response(200, $product-&toArray());
return 400;
// DELETE /v1/products/:id
// delete product by id
$app-&delete(function($request) use($product) {
$product-&delete();
return 204;
echo $app-&run(new Bullet\Request());PUT 请求意味着使用 PUT 请求正文的更新信息更新现有资源。此清单定义 PUT 处理程序,该程序读取 PUT 请求中的 JSON 文档,并使用 Eloquent 更新检索的 Product 对象的属性。然后,会使用此对象的 save() 方法将更新资源保存回数据库,并会将 200 Accepted 服务器响应代码返回给客户端,以此表示操作获得了成功并更新了资源。DELETE 请求意味着要从数据存储区删除 DELETE URL 中引用的资源,而上面的 DELETE 处理程序正在进行这样的操作:它调用检索 Product 对象的 delete() 方法从 MySQL 数据库删除产品记录。在本例中,我们使用了 204 No Content 响应代码和一个空白的响应正文来表示成功。下列图像显示了成功的 PUT 和 DELETE 请求。在这里需要注意的一个有趣现象是:上面的三个嵌套路由处理程序都使用了父处理程序中创建的 $product 实例。在父处理程序中定义常见例程或对象,然后在所有子闭包或块中使用它们,这样做可以使得重复的代码变得更少,使维护和更新变得更简单。步骤 6:支持多种格式大多数情况下,使用 JSON 请求和响应正文就可以了。但是,如果您想要支持另一种格式(比如 XML)会怎么样?使用 Bullet,您可以为不同格式定义自定义响应器,这样您就可以轻松处理此需求。为了说明这点,请考虑下一个清单,它为 /v1/products GET 端点的 XML 输出添加了支持:&?php
// set up Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// initialize Eloquent ORM and model
// snipped
// function to convert array to XML
function convert_array_to_xml($data) {
$xml = new SimpleXMLElement('&root/&');
foreach ($data as $r) {
$item = $xml-&addChild('product');
$item-&addChild('id', $r['id']);
$item-&addChild('name', $r['name']);
$item-&addChild('price', $r['price']);
return $xml-&asXml();
// initialize application
$app = new Bullet\App();
$app-&path('v1', function($request) use ($app) {
$app-&path('products', function($request) use ($app) {
// GET /v1/products[.xml|.json]
// list all products
$app-&get(function() use ($app)
$products = Product::all();
// handle requests for XML content
$app-&format('xml', function($request) use($app, $products) {
return $app-&response(200, convert_array_to_xml($products-&toArray()))
-&header('Content-Type', 'application/xml');
// handle requests for JSON content
$app-&format('json', function($request) use($app, $products) {
return $products-&toArray();
echo $app-&run(new Bullet\Request());应用程序对象的 format() 方法用于针对 XML 和 JSON 输出定义单独的回调处理程序。当 Bullet 遇到 URL /v1/products.xml 的请求,或者具有 'Accept: application/xml' 标头的 URL /v1/products 请求时,它会自动调用 XML 回调处理程序。在后一种情况下,Bullet 使用了自动内容协商功能,以便了解请求格式并提供相应的输出。从上一个清单中可以看出,此处理程序仅将从数据库检索到的一系列产品信息转换为 XML 文档,并将它返回给客户端。下列图像显示了输出。要以 JSON 格式获得输出,客户端应该使用 'Accept: application/json' 标头请求 URL /v1/products.json 或 URL /v1/products,如下列输出所示。可以类似的方式更新 POST 处理程序,因此它可以接受 XML 和 JSON 格式的输入。&?php
// set up Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// initialize Eloquent ORM and model
// snipped
// function to convert array to XML
function convert_array_to_xml($data) {
$xml = new SimpleXMLElement('&root/&');
foreach ($data as $r) {
$item = $xml-&addChild('product');
$item-&addChild('id', $r['id']);
$item-&addChild('name', $r['name']);
$item-&addChild('price', $r['price']);
return $xml-&asXml();
// initialize application
$app = new Bullet\App();
$app-&path('v1', function($request) use ($app) {
$app-&path('products', function($request) use ($app) {
// POST /v1/products[.xml|.json]
// create new product
$app-&post(function($request) use ($app) {
// handle requests for XML content
$app-&format('xml', function($request) use($app) {
$input = simplexml_load_string($request-&raw());
$product = new Product();
$product-&name = trim(htmlentities((string)$input-&name));
$product-&price = round(trim(htmlentities((string)$input-&price)), 2);
if ($product-&name && $product-&price) {
$product-&save();
return $app-&response(201, convert_array_to_xml(array($product-&toArray())))
-&header('Content-Type', 'application/xml');
return 400;
// handle requests for JSON content
$app-&format('json', function($request) use($app) {
$product = new Product();
$product-&name = trim(htmlentities($request-&name));
$product-&price = round(trim(htmlentities($request-&price)), 2);
if ($product-&name && $product-&price) {
$product-&save();
return $app-&response(201, $product-&toArray());
return 400;
echo $app-&run(new Bullet\Request());在这里,使用了 simplexml_load_string() 方法将发送给 /v1/products.xml 的基于 XML 的 POST 对象转换为 PHP 对象,并且使用此对象的属性填充新的 Product 实例。保存之后,会将新创建的 Product 资源的 XML 表示返回给客户端。下列图像显示了 XML POST 请求和响应的一个示例。如果客户端想使用 JSON,那么可以将 JSON 请求正文发送给 URL /v1/products.json。在本例中,Bullet 自动将 JSON 请求正文解码为对象,此对象可以转换为 Product 实例并保存到数据库。客户端接收所保存 Product 资源的 JSON 表示,如下所示。如前所述,通过将 'Accept: application/json' 标头作为 POST 请求的一部分发送给 URL /v1/products,可以获得相同的结果。步骤 7:处理错误并添加身份验证BulletPHP 随附提供了一个强大的事件处理系统,该系统可以基于特定的服务器代码、响应格式或异常类型来执行自定义操作。为了说明这点,请考虑下一个清单,该清单使用事件处理程序自动捕获异常,并将它们作为用 JSON 编码的数据包发送给客户端。&?php
// set up Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// initialize application
$app = new Bullet\App();
// global 'Exception' handler event
$app-&on('Exception', function($request, $response, Exception $e) use ($app) {
// send 500 error with JSON info about exception
$response-&status(500);
$response-&content(array(
'exception' =& get_class($e),
'message' =& $e-&getMessage()
// route handlers
// snipped
echo $app-&run(new Bullet\Request());下面是 API 如何响应异常的一个示例。在处理请求之前或之后,还可以使用此事件处理系统执行操作或自定义事件。一种常见用法是身份验证:可以针对受保护的路由触发自定义的 'authentication required' 事件,然后为此事件编写一个处理程序,以检查发送请求的客户端是否具有访问这些路由所需的凭据。下一个清单演示了一个简单的示例。在受保护的路由上触发了自定义 'auth' 事件;这将控制转交给了一个事件处理函数,它在进一步处理请求之前检查身份验证凭据(在本例中是 plaintext cookies)。&?php
// set up Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// initialize application
$app = new Bullet\App();
// runs when 'auth' event is triggered on protected API routes to check that
// credentials (here, plaintext cookies) are present
// replace with more complex authentication function in production
$app-&on('auth', function($request, $response) use ($app) {
if (!$request-&cookie('uid') == 'demo' || !$request-&cookie('pass') == 'demo') {
$response-&status(401);
$response-&send();
// unprotected API route to set authentication cookies
$app-&path('set-auth-cookies', function($request) use ($app) {
$app-&get(function() use ($app)
setcookie('uid', 'demo');
setcookie('pass', 'demo');
return 200;
// protected API route
$app-&path('v1', function($request) use ($app) {
$app-&path('products', function($request) use ($app) {
// trigger authentication event
$app-&filter('auth');
// route handler code
// snipped
echo $app-&run(new Bullet\Request());在此示例场景中,用户可以创建 cookies,方法是请求特殊的 /set-auth-cookies 路径;在生产环境中,用户可能需要通过注册来获得一个 API 密钥,并为每个请求提供它。下面的图像显示了 API 如何使用 401 Unauthorized 代码响应未授权的请求。步骤 8:部署到 Bluemix现在已经完成了 API 的所有编码,最后一步是部署它。如果在本地部署,则已经完成了相应的操作。跳到本部分末尾,因为末尾部分列出了可与 API 交互的一些有用工具。如果在 Bluemix 上部署,则需要使用 Bluemix 帐户,并需要下载和安装 Cloud Foundry 命令行客户端。按照下面的步骤完成部署过程。a. 创建应用程序清单应用程序清单文件告诉 Bluemix 如何部署应用程序。具体地讲,它指定要使用的 PHP 运行时环境("构建包")。在 $APP_ROOT/manifest.yml 中创建此文件,使用下列信息填充它。---
applications:
- name: products-api-[random-number]
memory: 256M
instances: 1
host: products-api-[random-number]
buildpack: 记住更新主机和应用程序名,让它们保持惟一,方法是更改它或为它添加一个随机数字。我使用的是 Cloud Foundry PHP 构建包,但还有其他选项可用。b. 为 Bullet 设置 URL 路由默认情况下,Cloud Foundry PHP 构建包使用 Apache 作为其 Web 服务器。Nginx 是一种轻型替代方法,在本步骤中,我们需要覆盖构建包的默认设置,以便使用 nginx 作为 Web 服务器。在开始之前,记住您可以从项目的 DevOps Services 源代码库获得此部分的所有文件。首先,需要创建一个 $APP_ROOT/.bp-config 目录,然后使用下列内容创建 $APP_ROOT/.bp-config/options.json。{
"WEB_SERVER": "nginx"
}此时,还必须为 nginx 设置 URL 重写规则,这样才能将 API 路径正确地传递给 Bullet 的 URL 路由器。首先,使用下列内容创建 $APP_ROOT/.bp-config/nginx/server-defaults.conf。
listen @{VCAP_APP_PORT};
server_name _;
fastcgi_temp_path @{TMPDIR}/nginx_fastcgi 1 2;
client_body_temp_path @{TMPDIR}/nginx_client_body 1 2;
proxy_temp_path @{TMPDIR}/nginx_proxy 1 2;
real_ip_header x-forwarded-
set_real_ip_from 10.0.0.0/8;
try_files $uri /index.然后,使用下列内容创建 $APP_ROOT/.bp-config/nginx/server-locations.conf。
# Some basic cache-control for static files to be sent to the browser
location ~* \.(?:ico|css|js|gif|jpeg|jpg|png)$ {
add_header P
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
# Deny hidden files (.htaccess, .htpasswd, .DS_Store).
location ~ /\. {
# pass .php files to fastcgi
location ~ .*\.php$ {
try_files $uri =404;
include fastcgi_
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_
fastcgi_pass php_
}c. 连接到 Bluemix 并部署应用程序凭借 'cf' 命令行工具使用 IBM id 和密码登录到 Bluemix。shell& cf api https://api.ng.Bluemix.net
shell& cf login更改到 $APP_ROOT 目录并将应用程序推送到 Bluemix。shell& cf push下面是您在此过程中看到的内容示例。此时,您的应用程序应该已经部署到了 Bluemix。但是还没有完成所有操作!d. 将 MySQL 服务实例绑定到应用程序现在已经部署了应用程序,但您仍然需要将它与 MySQL 数据库实例连接起来,这样您的 API 才有一些数据可供使用。为此,访问 Bluemix 管理仪表板并使用您的 id 和密码登录。您应该会看到 'Apps' 菜单栏列出了您的应用程序。选择您的应用程序,在生成的页面上,使用 'Add new service' 选项将 'mysql' 服务添加到您的应用程序。您现在应在 Bluemix 管理仪表板中看到 MySQL 服务实例已经绑定到了应用程序。具体地讲,如果您查看应用程序细节,应该能够在 VCAP_SERVICES 环境变量中看到 MySQL 访问凭据。e. 安装示例模式此时,可以使用如步骤 1 所示的示例模式初始化应用程序数据库。尽管在 Bluemix 环境中没有办法直接运行步骤 1 中的 SQL 命令,但应用程序包含一个名为 /install-schema 的特殊路径,可以通过浏览器请求它,以便设置数据库表和示例数据。尽管本文没有记录此路径,但可以在应用程序的源代码库中找到它。下面的图像显示了通过 /install-schema 路径成功安装模式的结果。6. 开始使用 REST API部署 REST API 之后,可以向它发送 GET、POST、PUT 和 DELETE 请求。Firefox 的
和 Chrome 的
扩展是通过浏览器构建和发送不同 API 请求类型的强大工具。本文中的大部分屏幕截图都是使用 Postman 扩展生成的。可以使用任意流行的客户端或服务器端编程语言向 API 提交请求:jQuery、PHP、Perl、Java 和 Python(以及其他语言)都支持 HTTP 请求提交和响应处理。本文还包含使用
的生动 API 演示,Swagger 为 API 探索提供了一个基于浏览器的工具。可以使用此演示添加和更新产品,删除产品或检索各个产品。下面的图像显示了实际的 Swagger 前端。结束语如本文所述,Bluemix 为在基于云的平台上创建和部署 REST API 奠定了坚实的基础。通过添加针对常见 REST 协定的 Bullet 灵活支持和 Eloquent 非常直观的 ORM,您可以获得快速制作原型和部署自定义 REST API 所需的一切内容。您可以从本文的 Devops Services 存储库下载本文实现的所有代码和所用 PHP 构建包的配置文件。建议您获取这些代码并运行它们,然后添加新的功能。我可以保证您不会有任何损失,而且可以学到更多的东西。
参考资料 查看 ,了解更多和 HTML5 相关的知识和动向。:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。:这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。,这是有关 Web 2.0 相关信息的一站式中心,包括大量 Web 2.0 技术文章、教程、下载和相关技术资源。您还可以通过
栏目,迅速了解 Web 2.0 的相关概念。:本专题为您提供了文章、教程、演示等丰富的学习资源,带您由浅入深地了解 Bluemix。此外,还有关于 Bluemix 的最新活动信息。欢迎大家访问学习。加入 。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
为灾难恢复构建应用,赢取现金大奖。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Web development, Cloud computingArticleID=972663ArticleTitle=在 Bluemix 上使用 PHP 和 MySQL 构建和部署 REST APIpublish-date=}

我要回帖

更多关于 ibm bluemix 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信