1.1 ecshop中最基本的一些知识与操作
①ecshop中的一些公用函数都会放在includes文件夹里,而这些公用函数几乎我们都可以用来参照一下就能轻松做出我们想要的其他功能了。init.php文件中包含以下代码,$smarty->assign('lang', $_LANG); 来设置ecshop的语言包。
ECShop的数据操作类文件是includes/cls_mysql.php,类名是cls_mysql。该类主要提供了下面
getAll($sql)和getAllCached($sql, $cached = 'FILEFIRST'):获取所有记录。
getRow($sql, $limited = false)和getRowCached($sql, $cached = 'FILEFIRST'):获取单行记录。
getCol($sqlse)和getColCached($sql, $cached = 'FILEFIRST'):获取某栏位的所有值。
getOne($sql, $limited = false)和getOneCached($sql, $cached = 'FILEFIRST'):获取单个数值。
query($sql):执行数据库查询。
autoExecute($table, $field_values, $mode = 'INSERT', $where = ''):数据库表操作。
1.获取单条记录
$GLOBALS['db']->getRow($sql);
getRow方法用来从数据库中获取满足条件的单行记录,或者说是第一条记录。getRowCached是它的缓存版本,cache key是该方法的第二个参数,如果缓存有效,直接返回缓存结果,否则重新执行数据库查询。缓存功能依此类推。
例如查询数据库表中的某个字段
$sql = "SELECT level FROM " . $ecs->table('users') . " WHERE user_name = '$vipaccount' ";
$row = $GLOBALS['db']->getRow($sql);
$level = $row['level'];
2.获取单一字段
$GLOBALS['db']->getOne($sql);
例如查询产品总数:
echo $GLOBALS['db']->getOne(‘SELECT COUNT(*) FROM ‘ . $GLOBALS['ecs']->table(‘goods’) ;
查询单一数据:
$sql = "SELECT order_amount FROM " . $GLOBALS['ecs']->table('order_info') . " WHERE order_id = '$order_id'";
$order_amount = $GLOBALS['db']->getOne($sql);
3.获取所有记录
$sql = 'SELECT * FROM ' . $GLOBALS['ecs']->table('suppliers') . ' ORDER BY suppliers_name ASC';
$GLOBALS['db']->getAll($sql);
$sql = "SELECT pay_id FROM " . $GLOBALS['ecs']->table('payment');
$GLOBALS['db']->getCol($sql);
getCol()得到是一个一维数组,而
5.执行sql语句
$GLOBALS['db']->query($sql); //执行删除(DELETE),插入(INSERT),更新(UPDATE)等操作可用此方法
6.把数组元素插入数据库
$parent['goods_number'] = ’1′;
$parent['parent_id'] = 0;
$GLOBALS['db']->autoExecute($GLOBALS['ecs']->table(‘cart’), $parent, ‘INSERT’);//table里面是要插入的表,第二个参数是数组
7.更新数据(数组形式)
$user = array(“username” => “ego”);
执行的SQL: UPDATE ecs_users SET username = ‘ego’ WHERE user_id = $user_id 。如果$user 中有两个元素,则 sql中的set 也写两个。
③echsop中的模板
ecshop有强大的模版机制,ECSHOP 结合Dreamweaver实现了一套模版机制,改动模版不再需要上传,而是在后台稍稍动动手设置一下就可以了。
ecshop采用smarty模板技术,Smarty是一个使用PHP写出来的模板引擎,是目前业界最著名的PHP模板引擎之一。它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码逻辑分离。
在php文件中使用assign方法把php变量传值给模板文件,例如:
$smarty->assign(‘action’, $action); //把php中的变量$action传值给模板文件(*.dwt)中的’action’变量,模板文件可用{$action}来输出此值。
使用display方法来指定当前的模板文件并输出到该文件显示到客户端,例如:$smarty->display(‘user_passport.dwt’);
1.2 补习一下前端的知识
1.输入框内容只可读。
3.如何获取下拉框中的value值。
<</span>body> <</span>form onsubmit="return formValidate()"> <</span>select name="select"id="order_status" onchange="a()"> <</span>option value="11">--请选择订单状态--</</span>option><</span>option value="0">--未确认--</</span>option> <</span>option value="1">--已确认--</</span>option> </</span>select> <</span>select name="select" id="shipping_status"onchange="b()"> <</span>option value="22">--请选择商品配送情况--</</span>option> <</span>optionvalue="0">--未发货--</</span>option> <</span>option value="1">--已发货--</</span>option><</span>option value="2">--已收货--</</span>option> </</span>select> <</span>input type="submit"value="提交" /> </</span>form> </</span>body> </</span>html>
javascript方法如下
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <</span>htmlxmlns="http://www.w3.org/1999/xhtml"> <</span>head> <</span>meta http-equiv="Content-Type"content="text/html; charset=gb2312" /> <</span>title>无标题文档</</span>title> <</span>scriptlanguage="JavaScript"> function formValidate() { var t1 =document.getElementByIdx_x("order_status"); alert(t1.options[t1.selectedIndex].value); var t2 =document.getElementByIdx_x("shipping_status"); alert(t2.options[t2.selectedIndex].value); returnfalse; } </</span>script> </</span>head>
这样点击提交按钮之后,便可以将value值得到并alert出选择的值。如果要将得到的
$firstparam = t1.options[t1.selectedIndex].value; $secondparam = t2.options[t2.selectedIndex].value; document.getElementByIdx_x("firstparam").value =$firstparam ; document.getElementByIdx_x("secondparam").value=$secondparam ;
页面上有如下代码,就可以把下拉框中的值赋给firstparam和secondparam。
<</span>tr> <</span>td><</span>input id="firstparam" name="firstparam" type="hidden" value="" /></</span>td> <</span>td><</span>input id="secondparam" name="secondparam" type="hidden" value=""/></</span>td> </</span>tr>
最后将页面的值传递给php代码中。这样写可以得到这两个参数。
$order_status = $_POST['firstparam']; $shipping_status = $_POST['secondparam'];
到此,整个过程完成:用户选择页面下拉框中的值后可以传递给php代码用来进行下一步的操作,比如写sql语句。
4.检查表单输入的密码是否相同的js函数
1.3 如何在ecshop后台增加左侧导航栏
1.后台添加导航
在languages\zh_cn\admin\common.php中增加
$_LANG['99_meicheng'] = ‘批量管理’; $_LANG['01_meicheng_user'] = ‘批量添加用户’;
2.添加导航链接
在
$modules['99_meicheng']['01_meicheng_user'] = ‘mc_user.php’;
其中 mc_user.php就是在admin文件夹中控制此次操作的php文件。
3.后续要添加的有
1.4 ecshop中读取csv文件内容
1.其实这个可以称的上是php中读取csv文件内容。例子是读取csv中的用户信息,后台注册用户。
用户操作界面代码:
<</span>div class="main-div"> <</span>form action="ck_user.php" method="post"enctype="multipart/form-data" name="theForm" > <</span>table width="100%" id="general-table"><</span>tbody id="1" > <</span>tr> <</span>td class="label">批量导入用户:</</span>td> <</span>td><</span>input name="upfile" type="file" id="upfile" size='35' /> <</span>spanstyle="color:#F00;">*</</span>span>文本为csv格式的:例 user.csv </</span>td> </</span>tr></</span>tbody> <</span>tr> <</span>td class="label"> </</span>td> <</span>td> <</span>inputtype="submit" value="批量添加用户" class="button" /> <</span>input type="hidden" name="act"value="mc_add" /> </</span>td> </</span>tr> </</span>table> </</span>form> </</span>div>
其中
后台读取cvs文件以及插入数据库中的代码:内容较多,请稳步这里 http://www.cnblogs.com/chenkaiadd/archive/2013/05/25/3099027.html
1.5 ecshop中将数据库表中的数据导出成csv文件
1.6 ecshop 中前端分页 (包含上架时间、价格、更新时间这一栏的链接、还有页中前一页、后一页、输入数字后点击确定跳转到指定页)
1.7 ecshop 中后台分页
1.8 ecshop 中ajax使用
①首先ecshop是如何定义ajax对象的。
②ecshop中ajax可以使用两种方式传递数据.一种是get方式,一种是post方式.
Ajax.call( 'user.php?act=is_registered', 'username=' + username, registed_callback , 'GET', 'TEXT', true, true ); Ajax.call('user.php?act=return_to_cart', 'order_id=' + orderId, returnToCartResponse, 'POST', 'JSON');
③ecshop中的 ajax可以是传递text数据,也可以是一个json对象。比如以下代码
goods.quick = quick; goods.spec = spec_arr; goods.goods_id = goodsId; goods.number = number; goods.parent = (typeof(parentId) == "undefined") ? 0 : parseInt(parentId); Ajax.call('flow.php?step=add_to_cart', 'goods=' + goods.toJSONString(), addToCartResponse, 'POST', 'JSON');
④ecshop ajax函数里面.第三个参数就是回掉函数的名称。比如以上代码addToCartResponse 这个函数就是ajax处理结果的回调函数.
⑤在ecshop的php代码中,一般是通过get或者post方式来接受函数。比如以下例子,如果接受的是对象。还需要用json数据格式来处理.比如以下
include_once('includes/cls_json.php'); $_POST['goods'] = json_str_iconv($_POST['goods']); 处理的返回结果,也需要是json格式发送给js die($json->encode($result));
下面以ecshop中的用户注册中验证用户名是否存在来分析。
在user_passport.dwt页面中显示注册界面
<</span>form action="user.php" method="post" name="formUser" onsubmit="return register();"><</span>table width="100%" border="0" align="left" cellpadding="5" cellspacing="3"> <</span>tr><</span>td width="13%" align="right">{$lang.label_username}</</span>td> <</span>td width="87%"><</span>input name="username" type="text" size="25" id="username"onblur="is_registered(this.value);" class="inputBg"/> <</span>span id="username_notice"style="color:#FF0000"> *</</span>span> </</span>td> </</span>tr> <</span>tr> <</span>td> </</span>td> <</span>td align="left"> <</span>input name="act"type="hidden" value="act_register" > <</span>input type="hidden" name="back_act" value="{$back_act}" /> <</span>input name="Submit" type="submit" value="" class="us_Submit_reg"> </</span>td> </</span>tr> </</span>table> </</span>form>
在页面中有
function is_registered( username ) { var submit_disabled = false; var unlen = username.replace(/[^\x00-\xff]/g, "**").length; if ( username == '' ) { document.getElementByIdx_x('username_notice').innerHTML = msg_un_blank; var submit_disabled =true; } if ( !chkstr( username ) ) { document.getElementByIdx_x('username_notice').innerHTML =msg_un_format; var submit_disabled = true; } if ( unlen < 3 ) { document.getElementByIdx_x('username_notice').innerHTML = username_shorter; var submit_disabled =true; } if ( unlen > 14 ) { document.getElementByIdx_x('username_notice').innerHTML =msg_un_length; var submit_disabled = true; } if ( submit_disabled ) { document.forms['formUser'].elements['Submit'].disabled = 'disabled'; return false; } Ajax.call('user.php?act=is_registered', 'username=' + username, registed_callback , 'GET', 'TEXT', true,true ); }
该函数调用 ajax方法。
Ajax.call( 'user.php?act=is_registered', 'username=' + username, registed_callback , 'GET', 'TEXT', true, true );
elseif ($action == 'is_registered') { include_once(ROOT_PATH . 'includes/lib_passport.php'); $username = trim($_GET['username']); $username = json_str_iconv($username); //将JSON传递的参数转码 if ($user->check_user($username) || admin_registered($username)) { echo 'false'; } else { echo 'true'; } }
check_user方法调用的是 \includes\modules\integrates\ecshop.php里的,不是父类
ajax方法中的第三个参数是一个回调函数的名称,该函数的实现也是在 user.js中。他的参数result正是上面函数echo的值(具体原因我暂时还不明白)
function registed_callback(result) { if ( result == "true" ) { document.getElementByIdx_x('username_notice').innerHTML = msg_can_rg; document.forms['formUser'].elements['Submit'].disabled = ''; } else { document.getElementByIdx_x('username_notice').innerHTML = msg_un_registered; document.forms['formUser'].elements['Submit'].disabled = 'disabled'; } }
该方法通过返回的结果 来判断在提示信息的文本框中到底显示什么内容。
这几天出现了一个问题,就是用自带的ajax.call函数不好用,于是想自己写一个,虽然最后证明自己写完了问题依然存在,可能不是ajax的方法,但是过程还是记录下来。
前台页面代码
<</span>input type="text" onblur=" is_specialed(this.value);
js 里方法如下
function is_specialed( service_special ) { if ( service_special == '向店内工作人员获取服务专员号'|| service_special == '') { document.getElementByIdx_x('special_error').innerHTML = "该服务专员号不存在2"; document.getElementByIdx_x('special_error').className = "error"; document.forms['formRegist'].elements['ifCanReg'].value = "1"; } // Ajax.call( 'user.php?act=is_specialed', 'service_special=' + service_special, specialed_callback , 'GET', 'TEXT', true, true ); //加上 自己写的ajax //调用ajaxstart xmlHttp=GetXmlHttpObject(); if (xmlHttp==null) { alert ("您的浏览器不支持AJAX!"); return; } var url="user.php?act=is_specialed"; url=url+"&sid="+Math.random() + "&service_special="+ service_special;xmlHttp.onreadystatechange=function () { //请求状态是4的时候,请求处理完成 if(xmlHttp.readyState==4) { //response是得到的后台输出数据。 var response = xmlHttp.responseText ;//这里将用回调函数用来显示错误提示信息 specialed_callback(response); } } xmlHttp.open("get",url,true); xmlHttp.send(); //调用ajax end } //创建xmlhttprequest对象 functionGetXmlHttpObject() { var xmlHttp=null; try { // Firefox, Opera 8.0+, Safari xmlHttp=newXMLHttpRequest(); } catch (e) { // Internet Explorer try { xmlHttp=newActiveXObject("Msxml2.XMLHTTP"); } catch (e) { xmlHttp=new ActiveXObject("Microsoft.XMLHTTP"); } }return xmlHttp; } function specialed_callback(result) { result = result.replace(/\s/g,""); if ( result == 'true' ) { //document.forms['formRegist'].elements['registsubmit'].disabled = '';document.forms['formRegist'].elements['ifCanReg'].value = "0"; } else { document.getElementByIdx_x('special_error').innerHTML = "该服务专员号不存在"; document.getElementByIdx_x('special_error').className = "error";//document.forms['formRegist'].elements['registsubmit'].disabled = 'disabled';document.forms['formRegist'].elements['ifCanReg'].value = "1"; } }
ajax里面使用的是get方法提交的。后台user.js里面可以通过$_GET['service_special'] 和$REQUEST['service_special']来得到。如果用ajax用post方法提交,则可以这样写
xmlHttp.open("POST",url,true); xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");//如果需要像HTML表单那样POST 数据用 setRequestHeader() 来添加 HTTP 头xmlHttp.send("service_special="+service_special);
相应的user.php 利用 $_POST['service_special'] 或$_REQUEST['service_special']来得到数据。代码为
elseif ($action == 'is_specialed') { include_once(ROOT_PATH . 'includes/lib_passport.php'); //$service_special = trim($_GET['service_special']); $service_special = trim($_POST['service_special']); //$service_special = trim($_REQUEST['service_special']); //$username = json_str_iconv($username); $sqlspecial = 'SELECT level FROM ' . $GLOBALS['ecs']->table('users') . " WHERE user_name = '$service_special'"; $row =$GLOBALS['db']->getRow($sqlspecial); $level = $row['level']; if($level ==1){ echo 'true'; } else { echo 'false'; } }
关于用get还是post 官方的说法是
与 POST 相比,GET 更简单也更快,并且在大部分情况下都能用。
然而,在以下情况中,请使用 POST 请求:
- 无法使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST 没有数据量限制)
- 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
1.9 ecshop中的后台权限管理
①以 admin\group_buy.php为例来说明权限的运用 。首先说一下,ecshop中每个php文件的头两行都是引用这样两句话,算是初始化吧。
define('IN_ECS', true); require(dirname(__FILE__) . '/includes/init.php');
随后我们看到,后台每个文件在执行方法之前都会有类似这样一个权限检查的方法
admin_priv('group_by');
function admin_priv($priv_str, $msg_type = '' , $msg_output = true) { global $_LANG; if($_SESSION['action_list'] == 'all') { return true; } if (strpos(',' . $_SESSION['action_list'] . ',', ',' . $priv_str . ',') === false) { $link[] = array('text' => $_LANG['go_back'], 'href' => 'javascript:history.back(-1)'); if ( $msg_output) { sys_msg($_LANG['priv_error'], 0, $link); }return false; } else { return true; } }
从这里我们可以看出,这里运用了php中的
语法为:strpos(string,find,start) 其中,string 为必需,是被搜索的字符串,find为必需,是要查找的字符。start为可选,是开始搜索的位置。另外一个知识点:如果需要对大小写不敏感的操作,则可以用函数 stripos() 来解决。
还有一个知识点是php中的
从类的注释中我们已经很清楚。该函数的功能就是查看 ,'group_by',
③那么系统是如何将数据库中的这些action_list 里的值存放到管理员的session中的呢?
控制后台登陆是在admin\privilege.php里 elseif ($_REQUEST['act'] == 'signin') 方法里有这样一段代码。
$_POST['username'] = isset($_POST['username']) ? trim($_POST['username']) : '';$_POST['password'] = isset($_POST['password']) ? trim($_POST['password']) : ''; $sql = "SELECT user_id, user_name, password, last_login, action_list, last_login". " FROM " . $ecs->table('admin_user') . " WHERE user_name = '" . $_POST['username']. "' AND password = '" .md5($_POST['password']) . "'"; $row = $db->getRow($sql); if ($row) { // 登录成功set_admin_session($row['user_id'], $row['user_name'], $row['action_list'], $row['last_login']); .......
可以看到管理员登陆时,利用
在admin\includes\lib_main.php里有这个方法的实现。
function set_admin_session($user_id, $username, $action_list, $last_time) { $_SESSION['admin_id'] = $user_id; $_SESSION['admin_name'] = $username; $_SESSION['action_list'] = $action_list;$_SESSION['last_check'] = $last_time; // 用于保存最后一次检查订单的时间 }
至此,可以看到整个流程已经非常清楚。管理员在数据库表中有一个字段 action_list, 管理员登陆之后将这个数据设置到$_SESSION 中。以后每次操作时都会调用admin_priv() 这个函数。来检验当前用户是否具有这个权限,如果没有则返回false ,程序终止。
④至于上图中点击勾后,便具有该权限。是如何实现的呢,权限等级,子权限等是如何实现的呢?参见:
1、将两个表复制,做好备份:
CREATE TABLE ecs_sessions_ori SELECT * FROM ecs_sessions;
CREATE TABLE ecs_sessions_data_ori SELECT * FROM ecs_sessions_data;
2、将原有的两张表更改成内存表:
ALTER TABLE `ecs_sessions` ENGINE = MEMORY
3、ecs_sessions_data表不能更改成内存表:
因为其中含有text字段,因而这个表不能被作为内存表使用。暂时先不改这个表了。
能像会话(Session)或缓存(Caching)一样方便操作和管理。
充分发挥内存引擎的特点:高速度,低延迟。
只读或读为主的访问模式(不适合频繁写)。
但是内存表的性能受制于单线程的执行效率和写操作时的表锁开销,这就限制了内存表高负载时的扩展性,特别是混合写操作的并发处理。此外,内存表中的数据在服务器重启后会丢失。
从这里我们可以暂时推断出,可能ecshop中要建这两个表的目的是为了提高效率。这两个表有一个不同点就是
这里又有另一个知识点:
下面开始讲解 ecshop中的session的原理。
PHP 中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可用。在函数或方法中无需执行 global $variable; 来访问它们。
$GLOBALS