转:

http://ninghao.net/blog/1441

作者:王皓
发布于:2014-05-30 13:16
更新于:2014-05-31 12:05

我们可以使用Laravel 框架为微信公众平台提供一个接口(API),这个接口可以处理微信发送过来的请求,根据这些请求里面的带的内容,你可以决定怎么样做出回应,比如返回用户想要查看的内容,处理用户想要做的事等等。在你的 Laravel 应用程序做出回应之前,先要判断一下,这个请求是不是来自微信那里。这篇文章,我们就介绍一下怎么样判断请求是不是来自微信,同时也简单介绍一下 Laravel 这个框架。

微信公众平台

首先你要做的是申请微信的公众帐号,目前分成两种,订阅号,还有服务号。订阅号普通人就可以申请,服务号应该需要公司才能申请。服务号比订阅号可以使用的接口多一些,就是服务号有更多的功能。我申请的是订阅号,如果有必要的话,去注册个公司,申请一个服务号也行。

假设你已经通过了公众帐号(订阅号或服务号),想要成为微信公众平台的开发者,你需要给微信提供一个地址,这个地址就应该是你的应用程序上的某个地址,一会儿我们用 Laravel 去创建这个地址。微信会往你提供的这个地址上发出一个请求,在这个请求里面,会包含一些内容,你的应用程序的这个地址,应该返回给微信特定的内容,这个内容已经包含在了微信给你发过来的请求里面,微信收到你的回应以后,如果确定是它想要的东西,这样,你就可以成为微信的开发者了。

成为微信开发者

其实通过这个验证是非常简单的,你只需要把应用接收到的微信发过来的 echostr 这个东西,给它原样返回去就行了。微信会发送一个 GET 类型的请求到你填写的地址上,GET 请求就相当于是用户直接在浏览器地址栏上输入了你的应用的地址,然后按了一下回车。只不过,这个请求带了一些额外的东西,在你的应用里面,你可以接收到这个请求里带的这些东西。在 PHP 里面,接收到 GET 请求里的内容,可以访问 $_GET 这个超级全局变量。比如微信发过来的 GET 请求里面,会包含 echostr,要得到 echostr 对应的内容,可以这样:

$_GET['echostr']

如果抛开 Laravel 框架,单纯用原始的 PHP 代码的话,可以这样来通过微信的成为开发者的验证:

echo $_GET['echostr'];

只需要上面这行代码。它的意思就是,把微信使用 GET 请求给我们发送过来的 echostr 里面的东西输出出来。假设这行 php 代码在你提供的地址的根目录下,名字是 index.php 。

然后登录微信公众平台以后,打开 功能 - 高级功能 - 成为开发者,在这里,会让你输入两样东西,一个就是微信要把请求发送到的你的应用的地址,另一样东西叫 token ,你可以随便怎么去定义这个 token 的内容,微信会用到你在这个 token里的填写的内容去生成最终的签名,一会儿我们再详细介绍一下。

都输入好以后,点击 提交,没有意外的话,你就可以顺利成为微信公众平台的开发者了。

等会儿,前面介绍的方法虽然可以让你成为开发者,但是我们并不希望这样做。想像一下,任何人都可以向你的应用的这个地址发送这样的 GET 请求。所以, 你需要一种方法验证一下,发送过来的请求是不是来自微信,因为你不想把用户相关的内容随便就响应回去。

验证请求的来源

微信的服务器会把订阅你的公众平台的用户发送到你的微信帐号的信息打个包发到你提供的地址上。你的应用程序接收到微信发过来的信息,处理一下,然后再做出一个响应。当你的程序接收到微信发过来的请求的时候,你得验证一下这个请求是不是从微信那里发过来的。

这个验证的过程大概是这样的,微信向你发送过来的请求里面,带着几样东西,一个微信会生成加密的签名(一串加密以后的字符串),还有几样其它的东西,你的应用程序可以接收到这个请求里面的这些东西的具体的内容,你需要在程序里面,利用这些东西,加上你在微信后台填写的 token ,去自己生成一个加密的签名,然后再用这签名跟微信发送过来的签名进行对比,如果两个签名是一样的,就说明这个请求是来自微信。这样你就可以安全的对这个请求做出必要的回应。

下面,我们再从技术的角度去解释一下这个过程。微信在给你发送的请求里面,会包含三样东西:

  • signature:加密的签名
  • timestamp:时间戳
  • nonce:一组随机的数字

在你第一次提交验证成为微信开发者的时候,在这个请求里面,还会包含另外一样东西:

echostr:一组随机的字符串

signature

这是微信通过特定的方法生成的一组加密的字符串。生成这个东西,用到了 token(你在微信后台自己填写的),timestamp(请求发生的时间),nonce(一组随机的数字)。微信会把这几样东西排一下顺序(字典序),再把排序之后的结果拼成一个字符串,再用 sha1 的方法对这个字符串进行加密,加密以后得到的结果就是这个 signature 。

在我们自己的应用里面,也需要用到同样的方法,去生成一个自己的 signature,再跟微信那头生成的 signature 对比一下。一样的话,说明请求是来自微信的。

在后面,我们再详细介绍怎么样使用代码去实现这个验证。下面,我们去准备一下应用需要的软硬件。

买一台服务器

我们就是简单测试一下,不过也需要一台服务器。早晚你得有这么一台:)可以试试国内的阿里云之类的云服务器,月付的话,1G 内存的服务器一个月 70 块上下,先买一个月试一下。可以自己按照 《CentOS:在阿里云上运行网站》这个课程自己去配置一下,不过最近阿里云提供了镜像市场,虽然没用过,但觉得想法非常好,就是别人做好的镜像,你可以直接用,有免费的,有收费的,这些镜像一般都拥有配置好的环境,你可以根据自己的需求选择适合自己的镜像。你把镜像想成是一块别人的硬盘就行了,硬盘里面,已经装好了你需要的东西。

不想麻烦去为网站备案,可以选择香港服务器与国外的服务器,阿里云最近也推出了香港节点的服务器,运行在上面的网站是不需要备案的。

你的服务器应该能运行 PHP 应用程序,推荐使用 LAMP 环境,Linux + Apache + Mysql + PHP,或者,你喜欢 Nginx ,可以把 Apahce 换成 Nginx 。注意我们要用的 Laravel ,需要 PHP 5.4 以上的版本。

Laravel 框架

我听说 Laravel 是一套非常优雅的 PHP 框架,受到了很多非常优秀框架的启发,比如 Ruby on Rails 。因为 Drupal 8 要来了,它使用了 Symfony 框架,所以就先去看了一下 Symfony ,看介绍的时候说 Laraval 也用到了不少 Symfony 的组件,而且语句优雅,你一定能喜欢上,看到这个广告语就忍不住去试了一下,打开 Laravel 的网站,我就知道不会错了。

我是第一次使用框架,觉得 Laravel 很好,用起来特别简单,了解一些 PHP 的基础,一点数据库,一点面向对象的编程方法,基本上就可以去用 Laravel 了。我觉得咱们都应该学一套框架,所以,今年打算出一些 Laravel 的基础课程,目前基本上已经定稿了,出完了 PHP 基础以后,就把 Laravel 的基础也制作出来。

PHP 5.5

Laravel 需要使用 PHP 5.4 以上的版本,先确认一下你的服务器上安装的 PHP 版本,可以使用命令 php -v  查看一下。如果 PHP 版本低于 PHP 5.4 ,先把旧版的 PHP 删除掉,重新安装新版的 PHP。假设你用的是 CentOS 系统,之前使用的是yum 安装的 PHP,想要移除现在安装的 PHP,可以这样:

yum remove php-common

然后再重新安装一下新版本的 PHP,可以先用 yum 在你的资源库里面搜索一下:

yum search php

如果你能看到一些 php55 ... 这样的东西,说明你可以直接使用 yum 安装 PHP5.5 ,如果看不到的话,你需要手工去安装必要的资源库,然后再重新试一下。安装 PHP 还有必要的扩展:

yum install php55u php55u-json php55u-mcrypt php55u-pdo php55u-mysqlnd

再运行一下 php -v 查看一下 PHP 的版本。

准备 Laravel

Laravel 唯一推荐的安装方式就是使用 Composer,所以你需要先去安装一下 Composer。安装完成以后,输入命令 composer,你应该可以看到一些命令,说明可以使用 Composer。

安装 Composer

进入到某个目录里面,比如你的用户的主目录

cd ~

使用 curl 命令去下载 Composer(注:国内访问速度很慢)

curl -sS https://getcomposer.org/installer | php

完成以后,查看一下目录里的东西

ls

你会看到这样一个文件

composer.phar

输入命令

php composer.phar

你应该能看到一些命令的帮助信息,不过我们不希望每次使用 Composer 的时候,都要使用 php 命令去运行它。你可以把composer.phar 移动到你的系统的环境变量里面的某个目录下面。这样你就可以在任何地方使用 composer 命令了。查看系统的环境变量,可以这样:

echo $PATH

返回的应该是一个目录的位置的列表,把 composer.phar 放在这里列出的任意一下目录的下面就行了。我把 composer.phar放到了 /usr/local/bin 下面。

mv composer.phar /usr/local/bin/composer

再试一次输入 composer 命令,你应该会看到一些命令的帮助信息。现在, 我们就可以使用 Composer 去安装 Laravel 了。

安装 Laravel

有了 Composer 以后,我们先进入到你想把 Laravel 放到的那个目录里面,任何目录都可以,等会儿我们再去设置虚拟主机。我打算把它放在这个目录下面:

/var/www/html/we.ninghao.net

先进入到这个目录:

cd /var/www/html/we.ninghao.net

然后使用 composer 命令去安装 Laravel

composer create-project laravel/laravel weixin --prefer-dist

这里用的是 composer 的 create-project 命令,去创建一个新的项目,创建的项目基于 Laravel 框架,项目的名字是weixin,这个名字你可以根据自己的需求随便去命名一下。注意如果你用的是国内的服务器,使用 composer 安装 Laravel 的过程非常慢,得多忍一会儿了。

完成以后,你会看到在目录里面,会有一个新的项目目录,这个目录的名字就是你在创建 Laravel 项目的时候自己指定的,在我这里,应该就是 weixin 。

Laravel 配置

使用 Laravel 框架开发应用的时候,你的代码一般都会放在 app 这个目录下面。比如应用的配置文件,路由,控制器,视图,模型等等。先去简单配置一下 Laravel,进入到 app/config 这个目录下面。

基本

cd weixin/app/config

编辑一下这个目录下面的 app.php 这个文件

vim app.php

使用 vim 编辑器,去编辑这个文件,按一下小  i 进入到编辑模式,然后找到 'debug' 这个关键词,把它的值修改成'true',意思就是开启应用的调试功能,注意在正式版的应用里面,需要关掉这个调试功能。

'debug' =>true,

再浏览器到 'url' 这个地方,把它的值修改成你的应用程序的地址,我打算把 we.ninghao.net 指向这个应用,所以可以这样:

'url' => 'http://we.ninghao.net',

你要根据自己的需求,修改这个 url 配置选项的值。另外这个配置文件里面,还有些其它的选项,比如时区,地域等等。

保存并退出这个文件。按下 esc,输入 wq 并回车。

数据库

下面,你需要给 Laravel 准备一个数据库,Laravel 支持很多种数据库系统,MySQL,Postgres,SQLite,SQL Server。你可以选择使用这里的任意一种数据库。一般,我们都是使用 MySQL,先去创建一个 MySQL 数据库,在命令行里,可以直接创建 MySQL 数据库,或者你可以使用图形工作,比如 PHPMyAdmin,或者 Sequel Pro 。

有了数据库以后,去打开 Laravel 里面的数据库相关的配置文件:

app/config/database.php

找到 mysql 数据库相关的配置,像下面这样去修改一下:

'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => '为 Laravel 准备的数据库的名字',
'username' => '你的数据库管理员',
'password' => '你的数据库管理密码',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),

完成以后,保存并退出。

权限

下面,我们还得修改一个目录的权限(app/storage),你需要给它写入的权限,一般,我们可以把这个目录的拥有者修改成你的 Web 服务器使用的用户,如果你用的是 Apache ,那么这个用户有可能就是 apache (CentOS)或者 www-data,具体你需要打开 Apache 的配置文件去看一下(httpd.conf)。如果你用的是 Nginx 服务器,参考这篇文章里面的修改目录和文件权限的部分。

修改目录的拥有者,可以像这样:

chown -R apache app/storage

上面这行命令,会把 app 下面的 storage 这个目录以及它所包含的子目录的拥有者修改成 apache ,修改完成以后,可以查看一下。

ls -la

虚拟主机

到目前为止,我们基本完成了 Laravel 部分的配置。下面,我们要做的是去在服务器里添加一个虚拟主机,把一个域名绑定到 Laravel 框架里面的 public 这个目录上,public 这个目录里包含向用户公开的东西,样式表,脚本文件,要用到图片,还包含一个 index.php 。

如何配置虚拟主机取决于你用的 Web 服务器。Nginx 服务器可以参考这篇文章里的配置虚拟主机部分。Apache 服务器可以参考这篇文章配置虚拟主机

虚拟主机的目录应该是 Laravel 里面的 public 这个目录。比如我的这个目录是在:

/var/www/html/we.ninghao.net/weixin/public

那么,上面这个地址,就应该是虚拟主机的主目录。我为这个目录绑定的域名是 we.ninghao.net。配置好以后,在地址里输入你的虚拟主机的域名,我这里就是 http://we.ninghao.net ,你应该会看到 Laravel 框架的默认的首页,上面有一个 Laravel 的标志,还有一行文字:You have arrived 。

创建与微信沟通的接口

下面,我们得去在应用里面创建一个跟微信沟通的接口,这个接口其实就是在应用里面的一个地址,这个地址可以去处理微信的请求,可以对请求做出相应的响应。Laravel 是一套基于 MVC 架构的框架,所以,处理请求用的是 MVC 里面的 C 这部分,C = Controller(控制器)。

注:我们会在 Laravel 基础课程里面详细去介绍 Laravel 里面的每个部分。

在 Laravel 里面,控制器也有同个类型,比如 RESTful 类型的控制器,有 Resource 类型的控制器。我打算用 Resource 类型的控制器去处理微信发过来的请求。可能创建 Resource 类型的控制器有点浪费,因为微信应该只会发送两种请求 GET 和 POST,所以控制器里的其它的方法就有点多余了,不过我们还是去创建一个 Resource 类型的控制器,可以顺序演示一样 Laravel 的 artisan 命令行工具的用法。

创建控制器

先进入到刚才我们创建的 Laravel 项目所在的目录,在我这里应该是:

/var/www/html/we.ninghao.net/weixin/

然后用 artisan 的 controller:make 命令,去创建一个 Resource 类型的控制器:

php artisan controller:make WeixinController

这条命令创建的控制器的名字是 WeixinController,这条命令会生成一个控制器文件,在你的 app/controllers 目录下面:

app/controllers/WeixinController.php

路由

有了控制器以后,我们可以去添加一条路由,然后让这个路由使用刚才创建的那个控制器去处理相应的请求。一条路由就是在应用程序里面,可能被请求的一个地址。在 Laravel 里面,所有的路由都在 app/routes.php 这个文件里面。打开这个文件,然后添加下面这些代码:

Route::resource('api/v1', 'WeixinController');

上面这行代码,就是为应用添加了一条路由。api/v1 ,这是路由的地址,WeixinController 就是处理请求这个地址用到的控制器。因为它是一个 Resource 类型的控制器,所以如果访问 api/v1 这个地址的话,会用控制器里面的 index() 这个方法去处理。

过滤器

在控制器的对应的方法里面,可以去处理微信的请求。不过在控制器的方法做出响应之前, 我们要去验证一下这个请求是不是来自微信。在 Laravel 里面,可以去给路由或者控制器去添加过滤器,过滤器的作用就是,在请求之前或者之后去做一些验证,比如用户是不是已经登录了。通过了验证,才会做出回应。在 Laravel 里面,已经包含了几个基本的过滤器,它们都是在 app/filters.php 文件里面定义的。

下面,我们自己去定义一个过滤器。用这个过滤器过滤掉来源不是微信的请求。打开 app/filters.php 文件,添加下面这几行代码:

Route::filter('weixin', function()
{
// 获取到微信请求里包含的几项内容
$signature = Input::get('signature');
$timestamp = Input::get('timestamp');
$nonce = Input::get('nonce'); // ninghao 是我在微信后台手工添加的 token 的值
$token = 'ninghao'; // 加工出自己的 signature
$our_signature = array($token, $timestamp, $nonce);
sort($our_signature, SORT_STRING);
$our_signature = implode($our_signature);
$our_signature = sha1($our_signature); // 用自己的 signature 去跟请求里的 signature 对比
if ($our_signature != $signature) {
return false;
}
});

上面这几行代码就是去创建了一个叫 weixin 的过滤器,这个过滤器做的事就是,先去获取到微信请求里面包含的几项内容,我们需要用到这几个东西,按照微信的方法加工一个自己的 signature ,然后再用这个 signature 去跟在请求里面包含的signature 去对比,如果不匹配的话,就返回 false 。

在代码里用到了 Input::get。它就是 Laravel 里面 Input 类的 get 方法,用它可以得到请求里面的包含的具体的内容。

下面,我们可以把这个过滤器用到 WeixinController 这个控制器上。打开这个控制器,然后添加下面这几行代码:

    public function __construct()
{
$this->beforeFilter('weixin', array('on' => 'get|post'));
}

它的意思就是,在这个控制器的构造函数(实例化类以后立即执行的函数)里面,添加了一个叫 weixin 的过滤器,这个过滤器会应用到所有的 get 和 post 类型的请求上。注意这个 weixin 的过滤器是作为 beforeFilter 添加进来的,也就是在请求之前就要使用这个过滤器。

现在,我们的 WeixinController 这个控制器就有了 weixin 这个过滤器的保护,任何用 GET 或 POST 方法发送过来的请求,都会先去确认一下这个请求是否是来自微信。

成为微信开发者

到目前为止, 我们已经为应用创建了一个跟微信沟通的接口(api/v1),当有请求发送到这个接口的时候,会先去验证一下这个请求是否是来自微信。如果是的话,才会使用相应的方法去处理这个请求。

成为微信开发者,我们需要在微信公众平台的后台,提供一个地址,还有一个 token 。token 我设置成了 ninghao。 现在我们可以把 url 设置成创建的这个接口的地址,在我这里应该就是:

http://we.ninghao.net/api/v1

访问 api/v1  这个地址的时候,是由 WeixinController 这个控制器里面的 index() 方法去处理。所以,我们需要在这个方法里,去返回微信发送过来的 echostr ,这样才能通过验证,成为微信公众平台的开发者。

    public function index()
{
return Input::get('echostr');
}

这样,WeixinController 这个控制器,现在看起来应该是这个样子的:

class WeixinController extends \BaseController {

    public function __construct()
{
$this->beforeFilter('weixin', array('on' => 'get|post'));
} /**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
return Input::get('echostr');
} // ..........
}

下一步

这篇文章里我们介绍了怎么样成为微信公众平台的开发者,怎么样验证请求是不是来自微信,除此以外,还不能做什么。下一步要做的就是,去设置一些方法,去处理订阅的用户从微信里发送的信息,根据这些信息的内容,我们的应用需要做出不同的回应。比如把用户的微信跟他在我们网站上的帐户绑定到一块儿。

名词

  • Laravel:是一套 PHP 框架,你可以用它创建 PHP 应用程序。
  • MVC:是设计程序的一种方法,它会把程序按功能分成几个部分。M 表示 Model (模型),一般用它来表示程序里面的数据。V 表示 View (视图),展示层面的东西都放到 View 里面。C 表示 Controller (控制器),它里面包含的是处理不同请求的代码。比如用户请求访问你的网站首页,控制器接受到这个请求以后,从 Model 那里调出数据,然后发送到 View 那里,View 会包装一下这些数据,把最终的结果显示给用户。
  • Symfony:是一套 PHP 框架,Drupal 8 里面会使用 Symfony 框架里面的几个组件,这篇文章里提到的 Laravel 也用到了不少 Symfony 的组件。可以肯定的是 Symfony 是一款优秀的框架。
  • Ruby on Rails:是一套用 Ruby 语言写的框架,你可以使用它快速的创建自己的应用程序。
  • 应用:是指 Application ,意思就是应用程序。在这篇文章里,你也可以把 “应用” 看成是一个网站。

相关资源

使用 Laravel 框架:成为微信公众平台开发者的更多相关文章

  1. 微信公众平台开发者中心服务器配置Token验证失败问题

    微信发展如火如荼,没有哪家的企业营销能避开微信不谈的,那像我们这种给客户实施项目的多多少少会涉及微信端的开发,本文只要给从未做过微信开发的人做一些简单的演示,行家里手们可以呵呵一下该干嘛干嘛去了. 微 ...

  2. python Django框架接入微信公众平台

    1.在接入微信公众平台之前,需要在微信公众平台配置好基本信息,如下: 这个时候点击“提交”按钮,会提示“Token校验失败”,不要着急,这是必然会出现的现象,先不要退出页面,保留各项输入的数据,按第二 ...

  3. MVC下c#对接微信公众平台开发者模式

    在ashx文件中进行HttpContext的处理: using System; using System.Collections.Generic; using System.Linq; using S ...

  4. C#微信公众平台开发者模式开启代码

    using System;using System.IO;using System.Text;using System.Web.Security; namespace HPZJ.Web.sys.exc ...

  5. 【转】C#微信公众平台开发者模式开启代码

    using System; using System.IO; using System.Text; using System.Web.Security; namespace HPZJ.Web.sys. ...

  6. 微信公众平台开发者认证,node

    纯属分享 app.js var express = require('express'); var path = require('path'); var app = express(); ; var ...

  7. [c#]asp.net开发微信公众平台(7)前6篇的整体框架demo源码

    这里给出的demo是具备整体框架的微信公众平台源码, 所谓demo就是拿过去就可以直接演示使用的东西,  当然不会具备非常详细的具体到业务层面.数据层面的东西, 每个人都可以在此基础上自由发挥,  只 ...

  8. 微信公众平台java开发详解(工程代码+解析)

    原文:http://blog.csdn.net/pamchen/article/details/38718947 说明:本次的教程主要是对微信公众平台开发者模式的讲解,网络上很多类似文章,但很多都让初 ...

  9. 用laravel搭一个微信公众号后台

    我使用的是laravel5.2, 早期版本可能不适合下面的方法. 在routes.php写下接收微信服务器post请求的路径: Route::post('wechatmp', 'WechatContr ...

随机推荐

  1. BZOJ 1461: 字符串的匹配

    Description 同上题. Sol KMP+树状数组. 写这题的时候我灰常naive...不管了...直接贴代码... Code /******************************* ...

  2. NOI2005 聪聪和可可

    Sol 记忆化搜索. \(f[u][v]\) 表示聪聪在 \(u\) ,可可在 \(v\) ,聪聪抓到可可的期望. 预处理出 \(u\) 到 \(v\) 最短路径编号最小的点,记为 \(g[u][v] ...

  3. 转:linux下bwa和samtools的安装与使用

    bwa的安装流程安装本软体总共需要完成以下两个软体的安装工作:1) BWA2) Samtools1.BWA的安装a.下载BWA (download from BWA Source Forge ) ht ...

  4. Git对象模型

    原文:http://gitbook.liuhui998.com/1_2.html 一.SHA 在git中,所有用来表示项目历史信息的文件,是通过一个40个字符的(40-digit)"对象名& ...

  5. css 图形,非常完美

    http://www.360doc.com/content/12/0327/13/8674_198243134.shtml

  6. ios UIWindow 错误使用导致无法接收motionEnded(摇一摇)函数

    今天遇到一个问题,第一次运行程序时,- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event函数无法调用,第二次就好了 ...

  7. 安装m2crypto报错swig error : Unrecognized option -builtin

    M2Crypto 是最完整的为 Python 包装 OpenSSL 的 RSA,DSA,DH,EC,HMACs,消息摘要,对称密码算法(包括AES)的一个库工具.而自从 M2Crypto 升级到版本 ...

  8. 错误日志中关于innodb的问题收集

    1.错误日志报告如下: ..... 120223 23:36:06 InnoDB: Compressed tables use zlib 1.2.3 120223 23:36:06 InnoDB: I ...

  9. vs版本转换工具

      [转]C#写的工程项目移植转换工具 – 支持VS2005/VS2010/VS2012/VS2013 经常用Visual Studio开发项目的是不是会经常遇到下面这种情况或者类似于这样的情况?用新 ...

  10. 【leetcode】Best Time to Buy and Sell 2(too easy)

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...