@sewise-dev
2016-12-26T02:07:13.000000Z
字数 12751
阅读 757
VPaas
| 编号 | 版本 | 说明 | 作者 | 日期 |
|---|---|---|---|---|
| 1 | v1.0 | 1.创建文档 | Seven | 2016-06-30 |
本框架基于Phalcon框架,对Phalcon框架进行了包装,使他可以自动通过配置来初始化Phalcon的系统组件
┌───────┬──── app 应用程序目录│ ││ ├──── Controllers 控制器程序目录│ ││ ├──── Models 数据库模型类目录│ ││ └──── Views 视图/模板文件目录│├──────────── config 配置文件目录│├──────────── docs 程序相关文档目录│├──────────── public web访问入口即index.php│├──────────── runtime 日志文件、文件缓存目录,要求可写,虽然以后日志可能不会写在这里,但框架本身的日志默认是在定个目录,所以需要可写权限
系统正式的配置文件请不要提交到版本库里,提交到版本库内的必须是配置文件的实例文件nginx配置try_files $uri $uri/ @rewrite;location @rewrite {rewrite ^/(.*)$ /index.php?_url=/$1;}
支持纯``php``文件和``volt``格式的视图文件,如果需要使用smarty,请自行重载``Joy\Application``类中的``setView``方法。Smarty的支持请使用``Phalcon\Mvc\View\Engine\Smarty``类;系统还支持``MustCache``和``Twig``模板引擎,你可以同时混用多种模板引擎。注意:如果你同时混用多种模板引擎时,不同模板引擎的模板文件是不能够互相包含和继承的。
通过配置 ningx 域名 account.sewise.com 至本项目 wechat/public 目录
本项目的配置文件根据环境的不同设置环境变量,分别为:localhost(本地环境)、development(测试环境)、production(生产环境)
复制config/web.config.php 文件为 config/web.+对应的环境变量+.php,修改缓存配置至对应服务器
<?php// 注意,本配置文件中所有关于组件名的设置均区分大小写$runTimePath = ROOT_PATH . '/runtime';return ['basePath' => ROOT_PATH . '/app', // 应用程序 的根目录'render' => 'json', //定义错误信息输出的页面,debug模式下此参数无效,如果为非debug模式,当设置为非json时会输出html;注意,请不要屏蔽此条配置'runtimePath' => $runTimePath, // 运行时生成的文件的目录,主要是用于保存日志'defaultNamespace' => 'Joy\Account', // 默认的命名空间'errorPage' => null, // 错误页面;允许使用PHP代码;系统提供了两个变量$code,$message,前者表示当前的页面的状态码,后者表示系统输出的错误内容。你可以根据自己的实际需要来显示错误页面'components' => [ // 设置系统需要加载的组件的属性'router' => [],'logger' => [ // 日志,允许同时开启多个日志'stream' => ['compress.zlib://' . $runTimePath . '/application.log.gz','']]// 'database'=>[''],// 'mongo'=>[],,'database' => [ // 数据库设置,可以设置多个数据库,每个数据库配置数组的键名为程序调用时使用的组件名'db' => ['adapter' => 'Mysql','host' => 'localhost','username' => 'DatabaseUser','password' => 'DatabasePassword','dbname' => 'DatabaseName','options' => [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8']]],'cache' => [// Msgpack暂时无法成功编译到php5.6,所以php5.6下暂时无法启用Msgpack支持'frontend' => 'Json', // 为支持与其他语言数据交换,请使用Json和Msgpack;支持Json、Msgpack、Data(php serialized),Output(PHP输出),None(不处理),Base64,IgBinary'backend' => [['adapter' => 'Redis','host' => '127.0.0.1','port' => 6379]]],'metadata' => ['adapter' => 'Memory',// 支持 Memory、Memcache、Redis// 公共参数:lifetime prefix// Memcache参数:host(主机) port(端口)persistent(是否长连接)// Redis参数:Redis(Redis链接url)'metaDataDir' => $runTimePath . '/metadata/']],'application' => ['controllersDir' => APP_PATH . '/controllers/','modelsDir' => APP_PATH . '/models/','views' => ['dir' => APP_PATH . '/views/','compiledPath' => $runTimePath . '/views/','compiledExtension' => $runTimePath . '/views/','compiledSeparator' => '%%','compileAlways' => $runTimePath . '/views/'],'baseUri' => '/'],'modules' => []];
<?php/*** 程序入口** @author seven <seven@sewise.com>* @date 2016-07-05*/$stage = getenv('APPLICATION_STAGE') ? getenv('APPLICATION_STAGE') : 'production';if ($stage == 'production') {defined('JOY_DEBUG') or define('JOY_DEBUG', false);} else {defined('JOY_DEBUG') or define('JOY_DEBUG', true);}defined('JOY_DB_DEBUG') or define('JOY_DB_DEBUG', false);defined('ROOT_PATH') or define('ROOT_PATH', dirname(__DIR__));defined('APP_PATH') or define('APP_PATH', ROOT_PATH . '/app');include ROOT_PATH . '/../framework/Joy.php';(new \Joy\Web\Application())->run();
<?phpnamespace Joy\Web\Controllers;/*** 默认控制器目录的路由配置信息** @author seven* @creat_time 2016-07-05*/class Routes extends \Phalcon\Mvc\Router\Group{public function initialize($paths){// Default paths(必要)$this->setPaths(array('namespace' => 'Joy\Web\Controllers'));// $this->add('/?([a-zA-Z0-9_-]*)\/?([a-zA-Z0-9_]*)(/.*)*',array("controller"=>1,"action"=>2,"params"=>3));//设置路由前缀$this->setPrefix('/v1/');//默认入口$this->add('', ['controller' => 'main','action' => 'index']);//清缓存$this->add('main/clearCache', array('controller' => 'main','action' => 'clearCache'))->setName('main-clearCache');/***********************************************************************//*** 未登陆用户接口*///用户注册API接口$this->addPost('user/register', ['controller' => 'normal','action' => 'register']);//用户登录API接口$this->addPost('user/auth', ['controller' => 'normal','action' => 'login']);//短信发送$this->addPost('sms/send', ['controller' => 'sms','action' => 'sendMsg']);/***********************************************************************/// $this->setPrefix('/v2/');/*** 已登陆用户信息操作*///只获取基本账号信息$this->add('user/accountInfo', ['controller' => 'user','action' => 'accountInfo']);//取得一个用户的资料$this->add('user/userInfo', ['controller' => 'user','action' => 'userInfo']);//基本信息修改$this->addPost('user/edit', ['controller' => 'user','action' => 'editAccountInfo']);//验证已登陆账号密码$this->addPost('user/authPass', ['controller' => 'user','action' => 'authPass']);//重置密码$this->addPost('user/reset', ['controller' => 'user','action' => 'resetPass']);//登录记录$this->addPost('user/record', ['controller' => 'user','action' => 'loginLog']);//更改套餐$this->addPost('user/rank', ['controller' => 'user','action' => 'editRank']);}}
<?phpnamespace Joy\Web\Controllers;use Joy\Web\Models\Account;use Joy\Web\Models\Tokens;/**1. 普通接口,处理用户的登录、注册行为等2. * @author seven3.*/class NormalController extends BaseController{/*** 校验用户权限,根据控制器名和动作名来校验用户的权限* $accessToken系统根据控制器名和动作名来自动生成* ```* $accessToken = substr(md5($module .** $controller . $action), 0, 6);* ```** @see \Joy\Web\Controller::beforeExecuteRoute()* @see \Joy\Web\Controller::checkAccess()4.列表项---*/public function checkAccess($accessToken){return true;}/*** 用户登录并返回登录令牌;出错时会输出错误提示** @param string $username* @param string $password* @return string | \Phalcon\Http\Response*/public function loginAction(){$user = $this->data;// 查找用户资料$account = Account::findFirst(['mobile = :mobile:','bind' => ['mobile' => $user['mobile']]]);// 账号不存在if ($account === false) {return $this->sendError(402, 'Invalid user');}// 非免密码登陆,则需要检测密码if ( ! $account->checkPassword($user['password'])) {return $this->sendError(402, 'Invalid password');}$token = new Tokens();$token->userId = $account->userId;// 有效时间为24小时$token->expire = date('Y-m-d H:i:s', time() + 24 * 3600);if ($token->save() === false)return $this->catchModelMessage($token);// 更新最后登陆时间$account->lastLogin = date('Y-m-d H:i:s');$account->save();// 返回结果return ['status' => 200,'data' => ['userId' => $account->userId,'access_token' => $token->token,'expire'=> $token->expire]];}/*** 保存一个用户* ```* {* "mobile": "13632517742",* "password": "b",* }* ```* @return \Phalcon\Http\Response|multitype:number*/public function registerAction(){$user = $this->data;$user['mobile'] =isset($user['mobile']) ? filter_var($user['mobile'], FILTER_SANITIZE_NUMBER_INT) : '';$user['password'] = isset($user['password']) ? filter_var($user['password'], FILTER_SANITIZE_STRING) : '';$account = new Account();if($user['password']){$account->password($user['password']);$user['password'] = $account->password;}unset($user['userId']);$this->db->begin();$account->assign($user);if($account->save() === false){$this->db->rollback();return $this->catchModelMessage($account);}else{$this->db->commit();return ['status' => 200,'data' => ['userId' => $account->userId,]];}}}
<?phpnamespace Joy\Web\Models;use Phalcon\Mvc\Model\Validator\Uniqueness;use Phalcon\Mvc\Model\Message;/*** 用户资料表,保存帐号相关的资料。仅用于注册用户的资料显示,发送验证短信、邮件等* PS:请面向对象编程* @author seven*/class Account extends \Phalcon\Mvc\Model{/*** 数据的正常标记* @var string*/const NOT_DELETE = 'N';/*** 数据的删除标记* @var string*/const DELETE = 'D';/*** 用户状态: 正常状态* @var int*/const STATUS_NORMAL = 1;/*** 用户状态:禁止状态* @var int*/const STATUS_FORBIDDEN = 2;/*** 普通用户* @var int*/const USER_NORMAL = 1;/*** 管理用户* @var int*/const USER_MANAGER = 2;/*** 用户帐号表的唯一ID* @Primary* @Identity* @Column(type="integer",nullable=true,column="uid")* @var integer*/public $userId;/*** 用户手机号* @Column(type="integer",nullable=true,length="11",column="mobile")* @var string*/public $mobile;/*** 用户密码,使用crypt函数进行加密* @Column(type="string",nullable=true,length="64",column="password"))* @see AccountInfo::checkPassword 或使用以下方法验证:* ```* if(crypt($password,$passwordHash)===$passwordHash)* {* return true;* }* ```* 注意:请不要直接通过此属性来设置密码;直接调用此属性设置密码将不会进行加密操作。* @see \Joy\Account\Models\Account::password* @var string*/public $password;/*** 密码干扰码* @Column(type="string",nullable=true,length="10",column="salt")* @var string*/public $salt;/*** 用户类型;管理用户,普通用户** @Column(type="integer",nullable=true,column="user_type")* @var int*/public $userType;/*** 用户帐号建立时间** @Column(type="datetime",nullable=true, column="creation_date")* @var string*/public $creationDate;/*** 用户的状态,如待激活,禁用** @Column(type="integer",nullable=false, column="account_status")** @var int*/public $accountStatus;/*** 最后登录时间** @Column(type="datetime",nullable=true, column="last_login")* @var string*/public $lastLogin;/*** 软删除标记,N表示正常状态,D表示已经删除** @Column(type="char",nullable=false,length="1",column="is_delete")* @var string*/public $isDelete;/*** 原始密码*/private $originPassword = null;/*** 数据表表名定义* @return string*/public function getSource(){return 'account';}/*** 初始化软删除标记* 初始化数据表外键关联*/public function initialize(){// $this->belongsTo ( 'userId', '\Joy\Account\Models\AccountInfo', 'userId', [// 'alias' => 'AccountInfo'// ] );$this->addBehavior(new \Phalcon\Mvc\Model\Behavior\Timestampable(['beforeCreate' => ['field' => ['creationDate','lastLogin'],'format' => 'Y-m-d H:i:s'],'beforeUpdate' => ['field' => 'lastLogin','format' => 'Y-m-d H:i:s']]));$this->addBehavior(new \Phalcon\Mvc\Model\Behavior\SoftDelete(['field' => 'isDelete','value' => self::DELETE]));$this->keepSnapshots ( true );$this->useDynamicUpdate ( true );}/*** 设置用户密码;执行此操作后,系统会根据提供的密码使用bcrypt算法进行加密。** @see \Phalcon\Security::hash* @link https://github.com/phalcon/cphalcon/blob/2.0.0/phalcon/security.zep#L139* @param string $password*/public function password($password){$this->originPassword = $password;$this->salt = $this->genSalt();$this->password = $this->encrypt($password, $this->salt);//$this->password = \Joy::$di->get('security')->hash($password);}/*** 检测密码的有效性** @param string $password* @return boolean*/public function checkPassword($password){$password = $this->encrypt($password, $this->salt);return $password === $this->password;//return \Joy::$di->get('security')->checkHash($password, $this->password);}/*** 对字符串进行加密处理** @param string $str 预加密字符串*/private function encrypt($password, $salt){return strtoupper(md5(strtoupper(md5($password . $salt))));}/*** 生成随机干扰码**/private function genSalt(){$hash = md5(time().rand(1, 9999999));return substr($hash, 0, 5);}/*** 数据校验,使用预定义的规则对提交到数据库的数据进行校验* 并对文本字段进行过滤处理** @return boolean*/public function validation(){//手机号格式检测if($this->mobile){if(!preg_match ( '/^1[3|4|5|7|8]\d{9}$/', $this->mobile, $match )){$message = new Message('手机号不正确', null, 'Error');$this->appendMessage($message);return false;}// 校验数据的唯一性$this->validate(new Uniqueness(array("field" => ["mobile"],'message' => '手机号已经存在')));if($this->validationHasFailed() ==true){return false;}}// 验证用户类别参数$this->validate(new \Phalcon\Mvc\Model\Validator\Inclusionin(["field" => "userType","domain" => [self::USER_NORMAL,self::USER_MANAGER],'message' => '用户类型有误']));if ($this->validationHasFailed() == true) {return false;}// 验证删除状态$this->validate(new \Phalcon\Mvc\Model\Validator\Inclusionin(["field" => "isDelete","domain" => [self::DELETE,self::NOT_DELETE],'message' => '删除状态有误']));if ($this->validationHasFailed() == true) {return false;}// 验证未经过加密的密码的格式if($this->originPassword){$pattern = '/[\x{30A0}-\x{30FF}\x{3040}-\x{309F}\x{4E00}-\x{9FBF}]+/u';if(preg_match ( $pattern, $this->originPassword, $match )){$message = new Message('密码不能为中文', null, 'Error');$this->appendMessage($message);return false;}if(preg_match ( '/\s+/', $this->originPassword, $match )){$message = new Message('密码不能含有空格', null, 'Error');$this->appendMessage($message);return false;}if (mb_strlen($this->originPassword, 'utf-8') != strlen($this->originPassword) || strlen($this->originPassword) < 6 || strlen($this->originPassword) > 20) {$message = new Message('密码仅限于6-20位的英文字符', null, 'Error');$this->appendMessage($message);return false;}}return true;}/*** 在数据验证前初始化所有不允许为null的字段*/public function beforeValidationOnCreate(){// 设置删除状态if($this->userType==null)$this->userType = self::USER_NORMAL;// 设置删除状态$this->isDelete = self::NOT_DELETE;//默认账号状态$this->accountStatus = self::STATUS_NORMAL;}/*** 添加前的额外数据校验** @return boolean*/public function afterValidationOnCreate(){// 检测帐号是否已经存在// 验证未经过加密的密码的格式if($this->originPassword==null && $this->password){$message = new Message('不允许直接设置密码', null, 'Error');$this->appendMessage($message);return false;}if($this->mobile==null){$message = new Message('手机号不能为空', null, 'Error');$this->appendMessage($message);return false;}if($this->password==null){$message = new Message('密码不能为空', null, 'Error');$this->appendMessage($message);return false;}}}
基于RESTful架构原则public function todo(){$url = "http://account.sewise.com/v1/user/accountInfo";$data = array('userId'=>22);$time = time();$accessHeaders = array('time'=>$time, 'token'=>'09e05eafd740fc13116c962d1a6872e0412d1ecd','version'=>'V1');try {$ret = Request::post($url,$data)->addHeaders($accessHeaders)->send();} catch (Exception $e) {return new Error('访问接口失败:'.$e->getMessage());}$ret = json_decode($ret,true);if(isset($ret['error'])) {return false;}print_r($ret);exit;}
HTTP请求状态返回格式
| 返回字段 | 字段类型 | 说明 |
|---|---|---|
| status | Integer | 请求返回码(详细请见状态表) |
| message | Array | 错误描述(请求错误时返回) |
| data | Array | 返回结果(请求成功时返回) |
错误样例
{
"status": 40013,
"message": {"0":"invalid appid"}
}
成功样例
{
"status": 200,
"data": {"access_token":"ACCESS_TOKEN","expires_in":7200}
}