ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
商城培训内容 一、目录结构(MVC模式) (1)视图(View) 存放在views文件夹下,主要存放显示页面的php文件 (2)模型(Model) 存放在models文件夹下,存放对数据库表的操作方法 (3)控制(Controller) 存放在controllers文件夹下,存放控制方法。从用户接受请求,讲模型与视图匹配在一起,共同完成用户的请求。 (4)其他文件 config文件夹:存放商城的备置文件。例如数据库文件(db.ini.php),备置文件(config.ini.php)等。 api文件夹:存放接口文件。例如快递接口文件(logistic.php)。 static文件夹:存放css文件,js文件,图片。 task文件夹:存放计划任务文件。 二、查找文件 例子:根据 `http://shop.yuanfeng.com/index.php?ctl=Buyer_Cart&met=cart` 地址查找文件 `index.php` 是入口文件。 `ctl=Buyer_Cart` 控制器文件路径 `shop/controllers/Buyer/CartCtl.php` `met=cart` 是 `CartCtl.php` 中的`cart`方法。 public function cart(){ $data = $this->getCart(); $this->data->addBody(-140, $data); if ($this->typ == 'json') { $new_data = array(); $sum = 0; $count = $data['count']; unset($data['count']); $new_data['count'] = $count; $cart_list = array_values($data); $new_data['cart_list'] = $cart_list; if ( !empty($cart_list) ) { foreach ($cart_list as $key => $val) { foreach ($val['goods'] as $k => $v) { $sum += $v['goods_num'] * $v['now_price']; } } } $new_data['sum'] = $sum; $this->data->addBody(-140, $new_data); }else{ include $this->view->getView(); } } $this->data->addBody(-140,$new_data); //返回数据 include $this->view->getView(); //加载页面 } 如果是加载页面,则页面的路径为 `shop/views/default/Buyer/CartCtl/cart.php` 在文件中有几种表示路径的方法: <?=$this->view->js?>/cart.js //对应文件 shop/static/default/js/cart.js <?= $this->view->js_com ?>/sppl.js //shop/static/common/js/sppl.js <?= $this->view->css ?>/tips.css //shop/static/default/css/tips.css <?=$this->view->img?>/mask.png //shop/static/default/images/mask.png 三、model方法(对数据表的操作) 例子: shop/models/Cart.php shop/models/CartModel.php `Cart.php`与`CartModel.php`这两个文件都是对购物车表进行操作的文件。Cart.php文件主要定义了增删改查这四个方法。 <?php if (!defined('ROOT_PATH')) { exit('No Permission'); } /** * * * @category Framework * @package __init__ * @author Yf <service@yuanfeng.cn> * @copyright Copyright (c) 2010, 朱羽婷 * @version 1.0 * @todo */ class Cart extends Yf_Model { public $_cacheKeyPrefix = 'c|Cart|'; public $_cacheName = 'cart'; public $_tableName = 'cart'; public $_tablePrimaryKey = 'cart_id'; /** * @param string $user User Object * @var string $db_id 指定需要连接的数据库Id * @return void */ public function __construct(&$db_id = 'shop', &$user = null) { $this->_tableName = TABEL_PREFIX . $this->_tableName; parent::__construct($db_id, $user); } /** * @param int $config_key 主键值 * @return array $rows 返回的查询内容 * @access public */ public function getCart($cart_id = null, $sort_key_row = null) { $rows = array(); $rows = $this->get($cart_id, $sort_key_row); return $rows; } /** * 插入 * @param array $field_row 插入数据信息 * @param bool $return_insert_id 是否返回inset id * @param array $field_row 信息 * @return bool 是否成功 * @access public */ public function addCart($field_row, $return_insert_id = false) { $add_flag = $this->add($field_row, $return_insert_id); //$this->removeKey($config_key); return $add_flag; } /** * 根据主键更新表内容 * @param mix $config_key 主键 * @param array $field_row key=>value数组 * @return bool $update_flag 是否成功 * @access public */ public function editCart($cart_id = null, $field_row = array(), $flag = true) { $update_flag = $this->edit($cart_id, $field_row, $flag); return $update_flag; } public function editCartNum($cart_id = null, $field_row = array()) { $update_flag = $this->edit($cart_id, $field_row); return $update_flag; } /** * 更新单个字段 * @param mix $config_key * @param array $field_name * @param array $field_value_new * @param array $field_value_old * @return bool $update_flag 是否成功 * @access public */ public function editCartSingleField($cart_id, $company) { $update_flag = $this->editSingleField($cart_id, $company); return $update_flag; } /** * 删除操作 * @param int $config_key * @return bool $del_flag 是否成功 * @access public */ public function removeCart($cart_id) { $del_flag = $this->remove($cart_id); //$this->removeKey($config_key); return $del_flag; } } ?> *商城中只能单表查询,不能多表联查。 *`Cart.php`只写最基本的增删改查方法,最好不要把其他的方法写入这个文件。 * editCart方法中的第3个参数表示的是修改数字符号为“+=” 还是“=”,例如editCart(1,array(goods_num=>3),true)),表示的是goods_num = goods_num + 3。editCart(1,array(goods_num=>3),false)),表示的是goods_num = 3。 几种经常使用的查找方法 `listByWhere` 返回带分页的数据 `getOne` 根据主键查找数据 `getByWhere` 根据条件查找数据 更多方法可以在`libraries/Yf/Model.php`中查找。 四、controller方法 例子:获取当前用户的购物车数据 地址为:`http://shop.bbc-builder.com/index.php?ctl=Buyer_Cart&met=cart` CartCtl.php中定义的cart方法上面已经写出。其中`$data = $this->getCart();`的getCart()方法如下: /** * 获取购物车列表 * * @author Zhuyt */ public function getCart() { $user_id = Perm::$row['user_id']; $Goods_BaseModel = new Goods_BaseModel(); $cord_row = array(); $order_row = array(); $cond_row = array('user_id' => $user_id); $order_row['cart_id'] = 'DESC'; $data = $this->cartModel->getCardList($cond_row, $order_row); foreach ($data as $key => $value) { $goods_detail = $Goods_BaseModel->getGoodsDetailInfoByGoodId($value['goods'][0]['goods_id']); if (!empty($goods_detail['common_base']['common_spec_name'])) { //商品规格颜色图 if (!empty($goods_detail['common_base']['common_spec_value_color'])) { $data[$key]['goods'][0]['goods_base']['goods_image'] = $goods_detail['common_base']['common_spec_value_color'][$value['goods'][0]['goods_base']['color_id']]; } } } if ($data) { $status = 200; $msg = __('success'); } else { $status = 250; $msg = __('failure'); } $this->data->addBody(-140, $data, $msg, $status); return $data; } 使用model方法先实例化对象。 $this->cartModel = new CartModel(); 获取数据后根据实际需求决定是返回数据还是加载页面。 五、view中显示数据 例子:购物车页面 <div class="cart_goods"> <ul class='cart_goods_head clearfix'><li class="done"><?=_('操作')?></li>
 <li class="price_all"><?=_('小计')?>(<?=(Web_ConfigModel::value('monetary_unit'))?>)</li>
 <li class="goods_num"><?=_('数量')?></li>
 <li class="goods_price"><?=_('单价')?>(<?=(Web_ConfigModel::value('monetary_unit'))?>)</li>
 <li class="goods_name"><?=_('商品')?></li>
 <li class="cart_goods_all cart-checkbox " style="float:left;"><input class="checkall" type="checkbox" data-type="all"><div class="select_all"><?=_('全选')?></div></li>
 </ul>
 <form id="form" action="?ctl=Buyer_Cart&met=confirm" method='post'>
 <ul class="cart_goods_list clearfix">
 <?php foreach($data as $key=>$val){?>
 <li class="carts_content">
 <div class="bus_imfor clearfix">
 <p class="bus_name">
 <input class="checkshop checkitem" type="checkbox" data-type="all">
 <span><i class="iconfont icon-icoshop"></i><a href="<?= Yf_Registry::get('url') ?>?ctl=Shop&met=index&id=<?=($key)?>"><?=($val['shop_name'])?></a></span>
 </p>
 </div>
 <table id="table_list" class="table_list">
 <tbody class="rel_good_infor">
 <?php foreach($val['goods'] as $k=>$v){ ?>
 <tr class="row_line">
 <td class="goods_sel cart-checkbox">
 <p>
 <input class="checkitem" type="checkbox" name="product_id[]" value="<?=($v['cart_id'])?>" <?php if($v['IsHaveBuy']){?>disabled="" title="您已达限购数量" <?php }?> >
 </p>
 </td>
 <td class="goods_img"><img src="<?=($v['goods_base']['goods_image'])?>"/></td>
 <td class="goods_name_reset">
 <a target="_blank" href="<?= Yf_Registry::get('url') ?>?ctl=Goods_Goods&met=goods&gid=<?=($v['goods_base']['goods_id'])?>"><?=($v['goods_base']['goods_name'])?></a>

 <?php if(isset($v['goods_base']['promotion_type'])): ?>
 <p class="sal_price">
 <?php if($v['goods_base']['promotion_type'] == 'groupbuy' && $v['goods_base']['down_price']): ?>
 <?=_('团购,直降:')?><?=format_money($v['goods_base']['down_price'])?>
 <?php endif;?>

 <?php if($v['goods_base']['promotion_type'] == 'xianshi' && $v['goods_base']['down_price']): ?>
 <?=_('限时折扣,直降:')?><?=format_money($v['goods_base']['down_price'])?>
 <?php endif;?>
 </p>
 <?php endif; ?>



 <p>
 <?php if(!empty($v['goods_base']['spec'])){foreach($v['goods_base']['spec'] as $sk => $sv){ ?>
 <?=($sv)?>&nbsp;&nbsp;
 <?php }}?>
 </p>


 </td>

 <td class="goods_price">
 <?php if($v['old_price'] > 0){?><p class="ori_price"><?=($v['old_price'])?></p><?php }?>
 <p class="now_price"><?=($v['now_price'])?></p>
 </td>
 <td class="goods_num">
 <?php
 if($v['buy_limit'] && !$v['IsHaveBuy'])
 {
 $data_max = $v['buy_residue'];
 }
 else
 {
 $data_max = $v['goods_base']['goods_stock'];
 }
 ?>
 <a class="<?php if($v['goods_num'] == 1){?>no_<?php }?>reduce" ><?=_('-')?></a><input id="nums" data-id="<?=($v['cart_id'])?>" data-max="<?=($data_max)?>" value="<?=($v['goods_num'])?>"><a class="<?php if($data_max <= 1){?>no_<?php }?>add" ><?=_('+')?></a>
 </td>
 <td class="price_all cell<?=($v['cart_id'])?>">
 <span class="subtotal"><?=($v['sumprice'])?></span>
 </td>
 <td class="done del"><a data-param="{'ctl':'Buyer_Cart','met':'delCartByCid','id':'<?=($v['cart_id'])?>'}"><?=_('删除')?></a></td>
 </tr>
 <?php }?>
 </tbody>
 </table>
 </li>
 <?php }?>
 </ul>
 </form>
</div> 五、其他 (1)在shop中调用其他项目的方法 `get_url_with_encrypt` 定义方法的文件:`libraries\__init__.php` //可以判断请求时间是否超过某个期限 function get_url_with_encrypt($key, $url, $formvars = array(), $typ = 'JSON', $method = 'POST') { $formvars['rtime'] = get_time(); $hash_row = $formvars; array_multiksort($hash_row, SORT_STRING); $hash_row['key'] = $key; $tmp_str = http_build_query($hash_row); Yf_Log::log('$tmp_str:' . $tmp_str, Yf_Log::INFO, 'get_url_with_encrypt'); Yf_Log::log('$url:' . $url, Yf_Log::INFO, 'get_url_with_encrypt'); $formvars["token"] = md5($tmp_str); Yf_Log::log($hash_row, Yf_Log::INFO, 'get_url_with_encrypt'); Yf_Log::log($formvars, Yf_Log::INFO, 'get_url_with_encrypt'); $rs = get_url($url, $formvars, $typ, $method); Yf_Log::log($rs, Yf_Log::INFO, 'get_url_with_encrypt'); return $rs; } 例如: 在shop中调用paycenter中的用户信息。 //会员的钱 $key = Yf_Registry::get('shop_api_key'); $formvars = array(); $user_id = Perm::$userId; $formvars['user_id'] = $user_id; $formvars['app_id'] = Yf_Registry::get('shop_app_id'); $money_row = get_url_with_encrypt($key, sprintf('%sindex.php?ctl=Api_User_Info&met=getUserResourceInfo&typ=json', Yf_Registry::get('paycenter_api_url')), $formvars); 在shop中验证接口合法性的方法`check_url_with_encrypt` 定义方法的文件:`libraries\__init__.php` function check_url_with_encrypt($key, $formvars = array()) { Yf_Log::log($formvars, Yf_Log::INFO, 'check_url_with_encrypt'); $token = $formvars['token']; unset($formvars['token']); $hash_row = $formvars; array_multiksort($hash_row, SORT_STRING); $hash_row['key'] = $key; $tmp_str = http_build_query($hash_row); Yf_Log::log('$tmp_str:' . $tmp_str, Yf_Log::INFO, 'check_url_with_encrypt'); Yf_Log::log('md5-key:' . md5($tmp_str), Yf_Log::INFO, 'check_url_with_encrypt'); //可以判断请求时间是否超过某个期限, 1分钟内 if ((get_time() - $hash_row['rtime'] < 60000) && $token == md5($tmp_str)) { return true; } else { return false; } } 例如:`shop\controllers\Api\Controller.php` if (!check_url_with_encrypt($key, $data)){ $this->data->setError(__('API接口有误,请确保APP KEY及APP ID正确'), 301); $d = $this->data->getDataRows(); $protocol_data = Yf_Data::encodeProtocolData($d); echo $protocol_data; exit(); } 底层防SQL注入: /** * 转义字符函数 * * @param mixed $content contents should be addslashes * * @return mixed $content * */ function quotes(&$content) { if (is_array($content)) { foreach ($content as $key => $value) { $content[$key] = quotes($value); } } else { $content = addslashes($content); } return $content; } 在`libraries\Yf\Model.php`文件的174行 $value = htmlspecialchars($value); 验证否登录方法在该模块下的控制器里controllers=>plugin 文件夹下Perm.php 添加免验证登录的控制器文件在此添加(一般用于未登录下的数据显示获取) public function checkPerm() { $data = new Yf_Data(); //无需权限判断的文件 $not_perm = array( 'Upload', 'Login', 'Api', 'ImApi', 'Index', 'Base_District', 'Connect_Qq', 'Connect_Weixin', 'Connect_Weibo', 'Transport', 'Shop', 'GroupBuy', 'Points', 'Voucher', 'Article_Base', 'Shop_Index', 'RedPacket', 'Supplier_Index', 'Supplier_Goods', 'PinTuan', 'Qr', 'Informationlist', 'Webconfig', 'Explore_UnExplore', 'Bargain_UnBargain', 'WxPublicTool_Index', 'Bill', 'Special_Column', 'WxPublicTool_SellerWx', 'Common', 'Distribution_NewBuyer_UploadWap', 'Distribution_NewBuyer_Goods', 'WeChatCs_Index', 'Test', 'Live', 'Shop_GoodsCat', 'Seller_Trade_Order', 'QiShou_Base', 'QiShou_Cash', 'QiShou_Evaluation', 'QiShou_Income', 'QiShou_Info', 'UploadAlbum', 'Api_Album', ); //不需要登录 if (!isset($_REQUEST['ctl']) || (isset($_REQUEST['ctl']) && in_array($_REQUEST['ctl'], $not_perm)) || (isset($_REQUEST['ctl']) && 'Api_' == substr($_REQUEST['ctl'], 0, 4)) || (isset($_REQUEST['ctl']) && 'WebPosApi_' == substr($_REQUEST['ctl'], 0, 10)) || (isset($_REQUEST['ctl']) && 'Goods_' == substr($_REQUEST['ctl'], 0, 6)) ||(in_array($_REQUEST['ctl'],$GLOBALS['extends_ini']))) { if (Perm::checkUserPerm()) { } } elseif (Perm::checkUserPerm()) { } else { // Perm::removeUserInfo(); if ('e' == $_REQUEST['typ']) { $url = Yf_Registry::get('url') . '?ctl=Login&met=login&typ=e'; if (request_string('forward_self')) { //$forward = '&forward=//:' . $_SERVER['HTTP_HOST'] . urlencode($_SERVER['REQUEST_URI']); $forward = '&forward=' . urlencode('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); $forward = str_replace('forward_self', 'x_self', $forward); $url = $url . $forward; } else { if (isset($_SERVER['HTTP_REFERER'])) { $forward = '&forward=' . urlencode($_SERVER['HTTP_REFERER']); $url = $url . $forward; } } location_to($url); } else { if('json' == $_REQUEST['typ'] && Perm::checkUserPerm()) { } else { $data->setError(__('需要登录'), 30); return $this->outputError($data); } } } } 日志添加文件在开发过程中对于特定节点进行日志监控通过此方法提添加 ``` $arra指要记录的数据 $log_name指要添加的日志名称 Yf_Log::log($array, Yf_Log::INFO, $log_name); ``` 操作日志则是在controllers=>plugin 文件夹下的log.php添加 public function addLog() { //同步,直接操作日志数据库 if (true || isset($ccmd_rows[$_REQUEST['ctl']][$_REQUEST['met']]['log'])) { $Yf_Registry = Yf_Registry::getInstance(); $ccmd_rows = $Yf_Registry['ccmd_rows']; $rights_id = @$ccmd_rows[$_REQUEST['ctl']][$_REQUEST['met']]['rid']; $data = array(); if (Perm::$login) { $data['user_id'] = Perm::$row['user_id']; // 玩家Id $data['user_account'] = Perm::$row['user_account']; // 角色账户 //$data['user_name'] = Perm::$row['user_realname'] ; // 角色名称 } else { } $data['action_id'] = $rights_id; // 行为id == protocal_id -> rights_id $data['log_param'] = $_REQUEST; // 请求的参数,|| 详细数据,可以通过controller结束赋值全部变量来或获取 $data['log_ip'] = get_ip(); // $logActionModel = new Log_ActionModel(); $log_id = $logActionModel->addAction($data, true); } //异步,队列操作 }