[关闭]
@sewise-dev 2016-12-26T02:07:13.000000Z 字数 12751 阅读 605

VPaas平台架构开发文档(应用层)

VPaas


更新历史

编号 版本 说明 作者 日期
1 v1.0 1.创建文档 Seven 2016-06-30

目录


framework框架使用说明

1 说明

本框架基于Phalcon框架,对Phalcon框架进行了包装,使他可以自动通过配置来初始化Phalcon的系统组件

2 目录结构

  1. ┌───────┬──── app 应用程序目录
  2. ├──── Controllers 控制器程序目录
  3. ├──── Models 数据库模型类目录
  4. └──── Views 视图/模板文件目录
  5. ├──────────── config 配置文件目录
  6. ├──────────── docs 程序相关文档目录
  7. ├──────────── public web访问入口即index.php
  8. ├──────────── runtime 日志文件、文件缓存目录,要求可写,虽然以后日志可能不会写在这里,但框架本身的日志默认是在定个目录,所以需要可写权限

3 关于配置文件

  1. 系统正式的配置文件请不要提交到版本库里,提交到版本库内的必须是配置文件的实例文件
  2. nginx配置
  3. try_files $uri $uri/ @rewrite;
  4. location @rewrite {
  5. rewrite ^/(.*)$ /index.php?_url=/$1;
  6. }

4 视图文件

  1. 支持纯``php``文件和``volt``格式的视图文件,如果需要使用smarty,请自行重载``Joy\Application``类中的``setView``方法。
  2. Smarty的支持请使用``Phalcon\Mvc\View\Engine\Smarty``类;系统还支持``MustCache````Twig``模板引擎,你可以同时混用多种模板引擎。
  3. 注意:如果你同时混用多种模板引擎时,不同模板引擎的模板文件是不能够互相包含和继承的。

5 域名配置:

  1. 通过配置 ningx 域名 account.sewise.com 至本项目 wechat/public 目录

6 配置文件:

本项目的配置文件根据环境的不同设置环境变量,分别为:localhost(本地环境)、development(测试环境)、production(生产环境)
复制config/web.config.php 文件为 config/web.+对应的环境变量+.php,修改缓存配置至对应服务器

  1. <?php
  2. // 注意,本配置文件中所有关于组件名的设置均区分大小写
  3. $runTimePath = ROOT_PATH . '/runtime';
  4. return [
  5. 'basePath' => ROOT_PATH . '/app', // 应用程序 的根目录
  6. 'render' => 'json', //定义错误信息输出的页面,debug模式下此参数无效,如果为非debug模式,当设置为非json时会输出html;注意,请不要屏蔽此条配置
  7. 'runtimePath' => $runTimePath, // 运行时生成的文件的目录,主要是用于保存日志
  8. 'defaultNamespace' => 'Joy\Account', // 默认的命名空间
  9. 'errorPage' => null, // 错误页面;允许使用PHP代码;系统提供了两个变量$code,$message,前者表示当前的页面的状态码,后者表示系统输出的错误内容。你可以根据自己的实际需要来显示错误页面
  10. 'components' => [ // 设置系统需要加载的组件的属性
  11. 'router' => [],
  12. 'logger' => [ // 日志,允许同时开启多个日志
  13. 'stream' => [
  14. 'compress.zlib://' . $runTimePath . '/application.log.gz',
  15. ''
  16. ]
  17. ]
  18. // 'database'=>[''],
  19. // 'mongo'=>[],
  20. ,
  21. 'database' => [ // 数据库设置,可以设置多个数据库,每个数据库配置数组的键名为程序调用时使用的组件名
  22. 'db' => [
  23. 'adapter' => 'Mysql',
  24. 'host' => 'localhost',
  25. 'username' => 'DatabaseUser',
  26. 'password' => 'DatabasePassword',
  27. 'dbname' => 'DatabaseName',
  28. 'options' => [
  29. PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
  30. ]
  31. ]
  32. ],
  33. 'cache' => [
  34. // Msgpack暂时无法成功编译到php5.6,所以php5.6下暂时无法启用Msgpack支持
  35. 'frontend' => 'Json', // 为支持与其他语言数据交换,请使用Json和Msgpack;支持Json、Msgpack、Data(php serialized),Output(PHP输出),None(不处理),Base64,IgBinary
  36. 'backend' => [
  37. [
  38. 'adapter' => 'Redis',
  39. 'host' => '127.0.0.1',
  40. 'port' => 6379
  41. ]
  42. ]
  43. ],
  44. 'metadata' => [
  45. 'adapter' => 'Memory',
  46. // 支持 Memory、Memcache、Redis
  47. // 公共参数:lifetime prefix
  48. // Memcache参数:host(主机) port(端口)persistent(是否长连接)
  49. // Redis参数:Redis(Redis链接url)
  50. 'metaDataDir' => $runTimePath . '/metadata/'
  51. ]
  52. ],
  53. 'application' => [
  54. 'controllersDir' => APP_PATH . '/controllers/',
  55. 'modelsDir' => APP_PATH . '/models/',
  56. 'views' => [
  57. 'dir' => APP_PATH . '/views/',
  58. 'compiledPath' => $runTimePath . '/views/',
  59. 'compiledExtension' => $runTimePath . '/views/',
  60. 'compiledSeparator' => '%%',
  61. 'compileAlways' => $runTimePath . '/views/'
  62. ],
  63. 'baseUri' => '/'
  64. ],
  65. 'modules' => []
  66. ];

7 入口文件:

  1. <?php
  2. /**
  3. * 程序入口
  4. *
  5. * @author seven <seven@sewise.com>
  6. * @date 2016-07-05
  7. */
  8. $stage = getenv('APPLICATION_STAGE') ? getenv('APPLICATION_STAGE') : 'production';
  9. if ($stage == 'production') {
  10. defined('JOY_DEBUG') or define('JOY_DEBUG', false);
  11. } else {
  12. defined('JOY_DEBUG') or define('JOY_DEBUG', true);
  13. }
  14. defined('JOY_DB_DEBUG') or define('JOY_DB_DEBUG', false);
  15. defined('ROOT_PATH') or define('ROOT_PATH', dirname(__DIR__));
  16. defined('APP_PATH') or define('APP_PATH', ROOT_PATH . '/app');
  17. include ROOT_PATH . '/../framework/Joy.php';
  18. (new \Joy\Web\Application())->run();

8 路由设置:

  1. <?php
  2. namespace Joy\Web\Controllers;
  3. /**
  4. * 默认控制器目录的路由配置信息
  5. *
  6. * @author seven
  7. * @creat_time 2016-07-05
  8. */
  9. class Routes extends \Phalcon\Mvc\Router\Group
  10. {
  11. public function initialize($paths)
  12. {
  13. // Default paths(必要)
  14. $this->setPaths(array(
  15. 'namespace' => 'Joy\Web\Controllers'
  16. ));
  17. // $this->add('/?([a-zA-Z0-9_-]*)\/?([a-zA-Z0-9_]*)(/.*)*',array("controller"=>1,"action"=>2,"params"=>3));
  18. //设置路由前缀
  19. $this->setPrefix('/v1/');
  20. //默认入口
  21. $this->add('', [
  22. 'controller' => 'main',
  23. 'action' => 'index'
  24. ]);
  25. //清缓存
  26. $this->add('main/clearCache', array(
  27. 'controller' => 'main',
  28. 'action' => 'clearCache'
  29. ))->setName('main-clearCache');
  30. /***********************************************************************/
  31. /**
  32. * 未登陆用户接口
  33. */
  34. //用户注册API接口
  35. $this->addPost('user/register', [
  36. 'controller' => 'normal',
  37. 'action' => 'register'
  38. ]);
  39. //用户登录API接口
  40. $this->addPost('user/auth', [
  41. 'controller' => 'normal',
  42. 'action' => 'login'
  43. ]);
  44. //短信发送
  45. $this->addPost('sms/send', [
  46. 'controller' => 'sms',
  47. 'action' => 'sendMsg'
  48. ]);
  49. /***********************************************************************/
  50. // $this->setPrefix('/v2/');
  51. /**
  52. * 已登陆用户信息操作
  53. */
  54. //只获取基本账号信息
  55. $this->add('user/accountInfo', [
  56. 'controller' => 'user',
  57. 'action' => 'accountInfo'
  58. ]);
  59. //取得一个用户的资料
  60. $this->add('user/userInfo', [
  61. 'controller' => 'user',
  62. 'action' => 'userInfo'
  63. ]);
  64. //基本信息修改
  65. $this->addPost('user/edit', [
  66. 'controller' => 'user',
  67. 'action' => 'editAccountInfo'
  68. ]);
  69. //验证已登陆账号密码
  70. $this->addPost('user/authPass', [
  71. 'controller' => 'user',
  72. 'action' => 'authPass'
  73. ]);
  74. //重置密码
  75. $this->addPost('user/reset', [
  76. 'controller' => 'user',
  77. 'action' => 'resetPass'
  78. ]);
  79. //登录记录
  80. $this->addPost('user/record', [
  81. 'controller' => 'user',
  82. 'action' => 'loginLog'
  83. ]);
  84. //更改套餐
  85. $this->addPost('user/rank', [
  86. 'controller' => 'user',
  87. 'action' => 'editRank'
  88. ]);
  89. }
  90. }

9 控制器文件实例:

  1. <?php
  2. namespace Joy\Web\Controllers;
  3. use Joy\Web\Models\Account;
  4. use Joy\Web\Models\Tokens;
  5. /**
  6. 1. 普通接口,处理用户的登录、注册行为等
  7. 2. * @author seven
  8. 3.
  9. */
  10. class NormalController extends BaseController
  11. {
  12. /**
  13. * 校验用户权限,根据控制器名和动作名来校验用户的权限
  14. * $accessToken系统根据控制器名和动作名来自动生成
  15. * ```
  16. * $accessToken = substr(md5($module .
  17. *
  18. * $controller . $action), 0, 6);
  19. * ```
  20. *
  21. * @see \Joy\Web\Controller::beforeExecuteRoute()
  22. * @see \Joy\Web\Controller::checkAccess()
  23. 4.
  24. 列表项
  25. ---
  26. */
  27. public function checkAccess($accessToken)
  28. {
  29. return true;
  30. }
  31. /**
  32. * 用户登录并返回登录令牌;出错时会输出错误提示
  33. *
  34. * @param string $username
  35. * @param string $password
  36. * @return string | \Phalcon\Http\Response
  37. */
  38. public function loginAction()
  39. {
  40. $user = $this->data;
  41. // 查找用户资料
  42. $account = Account::findFirst([
  43. 'mobile = :mobile:',
  44. 'bind' => [
  45. 'mobile' => $user['mobile']
  46. ]
  47. ]);
  48. // 账号不存在
  49. if ($account === false) {
  50. return $this->sendError(402, 'Invalid user');
  51. }
  52. // 非免密码登陆,则需要检测密码
  53. if ( ! $account->checkPassword($user['password'])) {
  54. return $this->sendError(402, 'Invalid password');
  55. }
  56. $token = new Tokens();
  57. $token->userId = $account->userId;
  58. // 有效时间为24小时
  59. $token->expire = date('Y-m-d H:i:s', time() + 24 * 3600);
  60. if ($token->save() === false)
  61. return $this->catchModelMessage($token);
  62. // 更新最后登陆时间 
  63. $account->lastLogin = date('Y-m-d H:i:s');
  64. $account->save();
  65. // 返回结果
  66. return [
  67. 'status' => 200,
  68. 'data' => [
  69. 'userId' => $account->userId,
  70. 'access_token' => $token->token,
  71. 'expire'=> $token->expire
  72. ]];
  73. }
  74. /**
  75. * 保存一个用户
  76. * ```
  77. * {
  78. * "mobile": "13632517742",
  79. * "password": "b",
  80. * }
  81. * ```
  82. * @return \Phalcon\Http\Response|multitype:number
  83. */
  84. public function registerAction()
  85. {
  86. $user = $this->data;
  87. $user['mobile'] =isset($user['mobile']) ? filter_var($user['mobile'], FILTER_SANITIZE_NUMBER_INT) : '';
  88. $user['password'] = isset($user['password']) ? filter_var($user['password'], FILTER_SANITIZE_STRING) : '';
  89. $account = new Account();
  90. if($user['password']){
  91. $account->password($user['password']);
  92. $user['password'] = $account->password;
  93. }
  94. unset($user['userId']);
  95. $this->db->begin();
  96. $account->assign($user);
  97. if($account->save() === false){
  98. $this->db->rollback();
  99. return $this->catchModelMessage($account);
  100. }else{
  101. $this->db->commit();
  102. return [
  103. 'status' => 200,
  104. 'data' => [
  105. 'userId' => $account->userId,
  106. ]];
  107. }
  108. }
  109. }

10 模型类文件实例:

  1. <?php
  2. namespace Joy\Web\Models;
  3. use Phalcon\Mvc\Model\Validator\Uniqueness;
  4. use Phalcon\Mvc\Model\Message;
  5. /**
  6. * 用户资料表,保存帐号相关的资料。仅用于注册用户的资料显示,发送验证短信、邮件等
  7. * PS:请面向对象编程
  8. * @author seven
  9. */
  10. class Account extends \Phalcon\Mvc\Model
  11. {
  12. /**
  13. * 数据的正常标记
  14. * @var string
  15. */
  16. const NOT_DELETE = 'N';
  17. /**
  18. * 数据的删除标记
  19. * @var string
  20. */
  21. const DELETE = 'D';
  22. /**
  23. * 用户状态: 正常状态
  24. * @var int
  25. */
  26. const STATUS_NORMAL = 1;
  27. /**
  28. * 用户状态:禁止状态
  29. * @var int
  30. */
  31. const STATUS_FORBIDDEN = 2;
  32. /**
  33. * 普通用户
  34. * @var int
  35. */
  36. const USER_NORMAL = 1;
  37. /**
  38. * 管理用户
  39. * @var int
  40. */
  41. const USER_MANAGER = 2;
  42. /**
  43. * 用户帐号表的唯一ID
  44. * @Primary
  45. * @Identity
  46. * @Column(type="integer",nullable=true,column="uid")
  47. * @var integer
  48. */
  49. public $userId;
  50. /**
  51. * 用户手机号
  52. * @Column(type="integer",nullable=true,length="11",column="mobile")
  53. * @var string
  54. */
  55. public $mobile;
  56. /**
  57. * 用户密码,使用crypt函数进行加密
  58. * @Column(type="string",nullable=true,length="64",column="password"))
  59. * @see AccountInfo::checkPassword 或使用以下方法验证:
  60. * ```
  61. * if(crypt($password,$passwordHash)===$passwordHash)
  62. * {
  63. * return true;
  64. * }
  65. * ```
  66. * 注意:请不要直接通过此属性来设置密码;直接调用此属性设置密码将不会进行加密操作。
  67. * @see \Joy\Account\Models\Account::password
  68. * @var string
  69. */
  70. public $password;
  71. /**
  72. * 密码干扰码
  73. * @Column(type="string",nullable=true,length="10",column="salt")
  74. * @var string
  75. */
  76. public $salt;
  77. /**
  78. * 用户类型;管理用户,普通用户
  79. *
  80. * @Column(type="integer",nullable=true,column="user_type")
  81. * @var int
  82. */
  83. public $userType;
  84. /**
  85. * 用户帐号建立时间
  86. *
  87. * @Column(type="datetime",nullable=true, column="creation_date")
  88. * @var string
  89. */
  90. public $creationDate;
  91. /**
  92. * 用户的状态,如待激活,禁用
  93. *
  94. * @Column(type="integer",nullable=false, column="account_status")
  95. *
  96. * @var int
  97. */
  98. public $accountStatus;
  99. /**
  100. * 最后登录时间
  101. *
  102. * @Column(type="datetime",nullable=true, column="last_login")
  103. * @var string
  104. */
  105. public $lastLogin;
  106. /**
  107. * 软删除标记,N表示正常状态,D表示已经删除
  108. *
  109. * @Column(type="char",nullable=false,length="1",column="is_delete")
  110. * @var string
  111. */
  112. public $isDelete;
  113. /**
  114. * 原始密码
  115. */
  116. private $originPassword = null;
  117. /**
  118. * 数据表表名定义
  119. * @return string
  120. */
  121. public function getSource()
  122. {
  123. return 'account';
  124. }
  125. /**
  126. * 初始化软删除标记
  127. * 初始化数据表外键关联
  128. */
  129. public function initialize()
  130. {
  131. // $this->belongsTo ( 'userId', '\Joy\Account\Models\AccountInfo', 'userId', [
  132. // 'alias' => 'AccountInfo'
  133. // ] );
  134. $this->addBehavior(new \Phalcon\Mvc\Model\Behavior\Timestampable([
  135. 'beforeCreate' => [
  136. 'field' => [
  137. 'creationDate',
  138. 'lastLogin'
  139. ],
  140. 'format' => 'Y-m-d H:i:s'
  141. ],
  142. 'beforeUpdate' => [
  143. 'field' => 'lastLogin',
  144. 'format' => 'Y-m-d H:i:s'
  145. ]
  146. ]));
  147. $this->addBehavior(new \Phalcon\Mvc\Model\Behavior\SoftDelete([
  148. 'field' => 'isDelete',
  149. 'value' => self::DELETE
  150. ]));
  151. $this->keepSnapshots ( true );
  152. $this->useDynamicUpdate ( true );
  153. }
  154. /**
  155. * 设置用户密码;执行此操作后,系统会根据提供的密码使用bcrypt算法进行加密。
  156. *
  157. * @see \Phalcon\Security::hash
  158. * @link https://github.com/phalcon/cphalcon/blob/2.0.0/phalcon/security.zep#L139
  159. * @param string $password
  160. */
  161. public function password($password)
  162. {
  163. $this->originPassword = $password;
  164. $this->salt = $this->genSalt();
  165. $this->password = $this->encrypt($password, $this->salt);
  166. //$this->password = \Joy::$di->get('security')->hash($password);
  167. }
  168. /**
  169. * 检测密码的有效性
  170. *
  171. * @param string $password
  172. * @return boolean
  173. */
  174. public function checkPassword($password)
  175. {
  176. $password = $this->encrypt($password, $this->salt);
  177. return $password === $this->password;
  178. //return \Joy::$di->get('security')->checkHash($password, $this->password);
  179. }
  180. /**
  181. * 对字符串进行加密处理
  182. *
  183. * @param string $str 预加密字符串
  184. */
  185. private function encrypt($password, $salt)
  186. {
  187. return strtoupper(md5(strtoupper(md5($password . $salt))));
  188. }
  189. /**
  190. * 生成随机干扰码
  191. *
  192. */
  193. private function genSalt()
  194. {
  195. $hash = md5(time().rand(1, 9999999));
  196. return substr($hash, 0, 5);
  197. }
  198. /**
  199. * 数据校验,使用预定义的规则对提交到数据库的数据进行校验
  200. * 并对文本字段进行过滤处理
  201. *
  202. * @return boolean
  203. */
  204. public function validation()
  205. {
  206. //手机号格式检测
  207. if($this->mobile){
  208. if(!preg_match ( '/^1[3|4|5|7|8]\d{9}$/', $this->mobile, $match )){
  209. $message = new Message('手机号不正确', null, 'Error');
  210. $this->appendMessage($message);
  211. return false;
  212. }
  213. // 校验数据的唯一性
  214. $this->validate(new Uniqueness(array(
  215. "field" => [
  216. "mobile"
  217. ],
  218. 'message' => '手机号已经存在'
  219. )));
  220. if($this->validationHasFailed() ==true){
  221. return false;
  222. }
  223. }
  224. // 验证用户类别参数
  225. $this->validate(new \Phalcon\Mvc\Model\Validator\Inclusionin([
  226. "field" => "userType",
  227. "domain" => [
  228. self::USER_NORMAL,
  229. self::USER_MANAGER
  230. ],
  231. 'message' => '用户类型有误'
  232. ]));
  233. if ($this->validationHasFailed() == true) {
  234. return false;
  235. }
  236. // 验证删除状态
  237. $this->validate(new \Phalcon\Mvc\Model\Validator\Inclusionin([
  238. "field" => "isDelete",
  239. "domain" => [
  240. self::DELETE,
  241. self::NOT_DELETE
  242. ],
  243. 'message' => '删除状态有误'
  244. ]));
  245. if ($this->validationHasFailed() == true) {
  246. return false;
  247. }
  248. // 验证未经过加密的密码的格式
  249. if($this->originPassword){
  250. $pattern = '/[\x{30A0}-\x{30FF}\x{3040}-\x{309F}\x{4E00}-\x{9FBF}]+/u';
  251. if(preg_match ( $pattern, $this->originPassword, $match )){
  252. $message = new Message('密码不能为中文', null, 'Error');
  253. $this->appendMessage($message);
  254. return false;
  255. }
  256. if(preg_match ( '/\s+/', $this->originPassword, $match )){
  257. $message = new Message('密码不能含有空格', null, 'Error');
  258. $this->appendMessage($message);
  259. return false;
  260. }
  261. if (mb_strlen($this->originPassword, 'utf-8') != strlen($this->originPassword) || strlen($this->originPassword) < 6 || strlen($this->originPassword) > 20) {
  262. $message = new Message('密码仅限于6-20位的英文字符', null, 'Error');
  263. $this->appendMessage($message);
  264. return false;
  265. }
  266. }
  267. return true;
  268. }
  269. /**
  270. * 在数据验证前初始化所有不允许为null的字段
  271. */
  272. public function beforeValidationOnCreate()
  273. {
  274. // 设置删除状态
  275. if($this->userType==null)
  276. $this->userType = self::USER_NORMAL;
  277. // 设置删除状态
  278. $this->isDelete = self::NOT_DELETE;
  279. //默认账号状态
  280. $this->accountStatus = self::STATUS_NORMAL;
  281. }
  282. /**
  283. * 添加前的额外数据校验
  284. *
  285. * @return boolean
  286. */
  287. public function afterValidationOnCreate()
  288. {
  289. // 检测帐号是否已经存在
  290. // 验证未经过加密的密码的格式
  291. if($this->originPassword==null && $this->password){
  292. $message = new Message('不允许直接设置密码', null, 'Error');
  293. $this->appendMessage($message);
  294. return false;
  295. }
  296. if($this->mobile==null){
  297. $message = new Message('手机号不能为空', null, 'Error');
  298. $this->appendMessage($message);
  299. return false;
  300. }
  301. if($this->password==null){
  302. $message = new Message('密码不能为空', null, 'Error');
  303. $this->appendMessage($message);
  304. return false;
  305. }
  306. }
  307. }

11 接口调用实例:

  1. 基于RESTful架构原则
  2. public function todo()
  3. {
  4. $url = "http://account.sewise.com/v1/user/accountInfo";
  5. $data = array('userId'=>22);
  6. $time = time();
  7. $accessHeaders = array('time'=>$time, 'token'=>'09e05eafd740fc13116c962d1a6872e0412d1ecd','version'=>'V1');
  8. try {
  9. $ret = Request::post($url,$data)->addHeaders($accessHeaders)->send();
  10. } catch (Exception $e) {
  11. return new Error('访问接口失败:'.$e->getMessage());
  12. }
  13. $ret = json_decode($ret,true);
  14. if(isset($ret['error'])) {
  15. return false;
  16. }
  17. print_r($ret);exit;
  18. }

12 返回结果说明:

HTTP请求状态返回格式

返回字段 字段类型 说明
status Integer 请求返回码(详细请见状态表)
message Array 错误描述(请求错误时返回)
data Array 返回结果(请求成功时返回)

错误样例
{
"status": 40013,
"message": {"0":"invalid appid"}
}
成功样例
{
"status": 200,
"data": {"access_token":"ACCESS_TOKEN","expires_in":7200}
}

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注