文章存档 » 五月 2011

使用不定个数的参数构造查询条件

通过get方法传过来0-3个参数,参数的个数不定,并通过这些参数构造出mysql查询语句.

下面是具体例子:

  • case1_url: www.***.com?id=1&name=2&gender=3/
  • case2_url: www.***.com?id=1&gender=3/
  • case3_url: www.***.com/

  • 在case1中我们传递了全部3个参数,这个很容易实现.

  • 在case3中我们没有传递参数,这个也很容易实现.
  • 但case2中只传递了部分参数应该怎么做呢?这个以前也纠结了不少时间,虽然实现了但方法都是很水的,这次请教了老段之后深深体会到了数据结构的强大之处.

解决方法

建立数据结构

建立2个数组,一个用来存储get中的变量名,另一个存储要构造mysql查询语句中的参数名;

$get_arrays = array(
        'id',
        'name',
        'gender',
);
//与前一个数组中的键值相对应,不过上面存的是get中的参数,这里是数据库中的名称.
$db_arrays = array(
        'user_id',
        'user_name',
        'user_gender',
);

构造查询串

利用循环将传递过来的参数存到新的数组中. 这里我们要新建一个数组query_array,用来存储查询语句 用到了两个函数:

//检查给定的键名或索引是否在数组中
bool array_key_exists(mixed $key , array $search)
//使用字符串$glue,将数组$pieces的所有元素连接起来
string implode ( string $glue , array $pieces )
join()// implode的别名
foreach($get_arrays as $key => $value)
{
        //判断参数是否通过get方法传了过来
        $judge = array_key_exists($value, $_GET);
        if($judge)
        {
                $array[$key] = "`{$db_arrays[$key]}`= '{$_GET[$get_array[$key]]}'";
                //将要查询的变量及值用"="连接,写入数组中,此时array数组形如:$array=('id=1', 'gender=3');
        }
        $condition = join(" and ", $array);     // 使用"and"将各项条件连接起来
}?>

注:本文中的示例代码中未对输入进行转义,请勿应用在生产环境中。

Mysql错误号#1062解决办法

最近做新的HOJ的后台管理功能,实现一个简单的交互界面,能够让管理员方便地添加比赛。但是实际编码的时候发现一些数据库的问题:

  1. 存储比赛的表中,比赛的编号不是连续的。
  2. 比赛的编号不是自动增加的。
  3. 想要添加比赛,就要手动设置比赛的编号。

手动设置比赛的编号显然十分麻烦,不符合方便添加比赛的设计需求。那么就要把比赛编号字段设置成自动增加的。于是,输入了一条命令:

ALTER TABLE Contests CHANGE Contestid Contestid INT(11) NOT NULL AUTO_INCREMENT;

结果,我还是异想天开了——Mysql抛出了 #1062号错误:

ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '1' for key 'PRIMARY'

仔细分析以后发现了出错原因。比赛的表(Contests)中原本是有数据的,比赛的编号是从0起递增的。修改Contestid字段到AUTO_INCREMENT时,Mysql尝试将Contestid=0的这行的Contestid修改成1,但是原表中已经存在了Contestid=1的项目,而对于主键Contestid来说,值应该是唯一的,所以会报错说出现重复值‘1’。那这样一来,该如何修改Contestid字段,使其变成自动增加的呢?

方法一:

找出了这么一个愚钝的方法,步骤如下:

  1. 导出Contests表中的数据到temp.sql文件。
  2. 删除Contests表中的所有数据。
  3. 修改Contestid字段为AUTO_INCREMENT。
  4. 导入temp.sql,完成。

方法二:

上面的方法显然很麻烦,而且如果数据量特别大的话,将会十分耗时。后来我又尝试了另一个方法:

  1. 修改Contestid为0的一行,使其Contestid为大于0的整数。当然不能和表中其他行的Contestid重复。
  2. 修改Contestid字段为AUTO_INCREMENT。
  3. 将步骤1中的那一行的Contestid改回0,完成。事后可能需要修改AUTO_INCREMENT记录。

这里假设Contests表和其他表没有关联。如果和其他表有关联,那么只要依照关联关系,利用上面的方法适当修改即可。

Ajax简介 – 异步交互

主讲人朱玺
题目Ajax简介 – 异步交互
时间2011-5-8
 相关下载

简单介绍

Ajax——“Asynchronous JavaScript and XML”(异步JavaScript和XML)…看上去很抽象吧。 还是再介绍介绍JavaScript和XML吧。

  • JavaScript:是一种脚本语言,结构简单,使用方便,其代码可以直接放入HTML文档中,可以直接在支持JavaScript的浏览器中运行.——总而言之就是一种在客户端运行的语言。
  • XML:可扩展标记语言,Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具。——原来是处理信息用的。

Ajax是干什么的?

通过 AJAX,您的 JavaScript 可使用 JavaScript 的 XMLHttpRequest 对象来直接与服务器进行通信。通过这个对象,您的 JavaScript 可在不重载页面的情况与 Web 服务器交换数据。即实现网页与服务器的异步通信功能。

而传统网页同步处理请求的方法是用户触发一个HTTP请求到服务器,服务器对其进行处理后再返回一个新的HTHL页到客户端——用户每次都要浪费时间和带宽去重新读取整个页面。造成的结果是在网速较低或需要传输的页面较大的情况下原页面会锁死。大大降低用户的浏览体验。

对比传统网页交换数据的方法使Ajax技术拥有两大优点:

  • 可以像桌面应用程序只同服务器进行数据层面的交换,减轻服务器负担,缩短了用户等候时间。
  • 加快了页面的相应速度,大大提高了页面的交互性。使因特网应用程序更小、更快,更友好。

原理图解

传统网页交互方式

页面直接与服务器交换数据,两次user activity之间的世界就是用户页面锁死的时间。

Sync Request

通过Ajax技术的交互方式

Ajax技术在用户页面和服务器之间加入了一个中间层(Ajax engine),用户提出的请求先提交到中间层,中间层再分析用户提交的请求后确定向服务器提交的请求。最后根据服务器返回的数据通过JavaScript实时将结果显示到用户页面上。——以上的数据交换都是在中间层上完成的,所以不会造成整个页面的锁死。加强了用户体验。

Async Request

Ajax小应用

Ajax Demo Show

具体实现

  • 文件组成:有3个文件index.htm ajax.js 和 telltimeXML.php 组成。
  • 核心部件:其中的关键就在于ajax.js文件里的XMLHttpRequest 对象。

XMLHttpRequest对象的属性和方法见文末的附录

我们来重点分析一下ajax.js文件中 getServerTime() 和 useHttpResponse()两个函数。

最前面的getXMLHTTPRequest()函数是针对不同浏览器来建立 XMLHttpRequest 对象,有兴趣的童鞋可以自行google其中的奥妙。

先来看 getServerTime()

var myurl = “telltimeXML.php”; var myRand = parseInt(Math.random() * 999999999); var modurl = myurl + “?rand=” + myRand;

这里构造了一个open函数里的url参数,即Ajax需要发出的服务器请求。这里使用了一Math.random()具体作用后面会再做介绍。

http.open(“GET”, modurl, true);

设定对服务器请求的一些参数:请求类型GET, url:为前面生成,true:异步传输数据。

http.onreadystatechange = useHttpResponse;

设定当readyState 属性改变时,就调用 useHttpResponse() 函数。这里作一下说明,readyState 属性是根据XMLHttpRequest 对服务器请求的不同状态而自动发生变化。具体可参见对readyState 属性的介绍。

http.send(null);

最后发送请求就可以了。

然后来看 useHttpResponse() 函数对readyState 属性改变时所做出的相应。

我的代码是对readyState == 4 和 status == 200 同时成立时(即一般情况下Ajax对服务器请求完成,且服务器返回相应已就绪)对服务器返回的responseXML(包含服务器时间信息)进行处理,并利用javascript对网页进行修改,做到无刷新的数据交换。

在其他情况下就显示一个Loading…表示网页正在后台与服务器交换信息。

Ajax的几个缺陷

缓存

由于 XMLHttpRequest 对象是通过url来对服务器进行请求的,这就不可避免的与浏览器的缓存机制产生了冲突。简单的说,由于服务器端的信息可能是时刻改变的,浏览器缓存则是以url为标准记录缓存。当通过同一url访问服务器时,可能服务器端的数据已经改变,而浏览器却只是读取了本地缓存,而使在网页上显示的信息和在服务器上的信息不一致。造成问题。所以在getServerTime() 函数中我使用了一个Math.random()函数来使每次请求的url不一致,来欺骗浏览器,使其不读取缓存。在讨论中段哥也提到了这个问题,并指出这个方法并不科学,因为random()函数也有小概率产生同样的url同样可能造成问题。现在正确的做法是先读取服务器端返回的状态,若为304则表明服务器端数据未修改,则可以直接读取缓存,否则需从服务器端重新读取信息。

历史

由于Ajax对网页进行的是实时改变,并不改变网页的url,所以会导致浏览器没有办法记录访问地址,并且无法与好友分享网页上的信息。

谢谢大家耐心阅读。

相关下载

附录

参考文章:Ajax初步

在此摘录XMLHttpRequest对象的一些属性和方法。

如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法:

open(method,url,async)   method:请求的类型;GET 或 POST
                    url:文件在服务器上的位置
                    async:true(异步)或 false(同步)
send(string)            string:post请求中所要传输的数据。
onreadystatechange      存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState          存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
                    0: 请求未初始化
                    1: 服务器连接已建立
                    2: 请求已接收
                    3: 请求处理中
                    4: 请求已完成,且响应已就绪
status              返回的服务器状态,一般正常的话为200。
responseText            获得字符串形式的响应数据。
responseXML         获得 XML 形式的响应数据。

使用不定个数的参数构造查询字符串

寒假开始制作Cyber-Reader写CDB类库的时候,就有一个查询是要求写出一个,具有可变参数个数的函数,类似于sprintf,fsql定义了数据格式,v1, v2等变量定义了要替换的值,然后将替换后的字符串作为数据库查询进行执行.

这个东西我纠结了好久,也想了不少方法,最后因为开学了没有写完,里面不少东西都是老段完成的.现在说说关于这个查询时遇到的问题和解决的方案.

先举一个实现后的例子:

这其实就是一个select语句,其中不同的地方就是第一个参数中的name的值%s用后面的’glove’来替换,site的值%s用后面的’glovely.info’来替换,这些可以替换的参数是不限定个数的. 也就是说这个函数像我们用的sprintf一样,是带有不定个数的参数的.

最初我的想法是得到用户的输入,将其传递给sprintf,这样变将要赋值的参数通过sprintf完成,然后最后得到的结果便是我们要执行的mysql命令.下面是实现的方法.

实例1:

mysql命令 return $result; if(is_bool($result)) return $result; else return mysql_fetch_array($result); //根据所得值是bool还是array来确定不同的返回值类型. } ?>

虽然有部分命令可以执行,但这显然不是一个很好的办法,毕竟这里要求的功能不是和sprintf一模一样的.

下面便是我们现在的CDB类库中使用的queryf. 它的思路:

得到输入的命令,通过判断其中%的位置和数量,来找到要传入的数据类型和数据个数,并进行相应的错误判断. 实例2:

<?php const NUM = ‘d’; const STR = ‘s’; const RAW = ‘r’; const ESC = ‘%’;

function queryf() { $args = funcgetargs(); //获得输入的命令 if( ($argCount = count($args)) == 0 ) //检查命令长度是否为0 return false; $format = $args[0]; //命令的第一部分 $argpos = 1; $escpos = false; $vpos = 0; $sql = ”; while(true) { $escpos = strpos($format, CDB::ESC, $vpos); //查找符号”%”在字符串$format中出现的位置,偏移量为$vpost,初始为0. if($escpos === false) //第一次查找%位置时$escpos的值应该是false { $sql .= substr($format, $vpos); //找到字符串$format中初始位置到$vpost字符并存入$sql中 break; } $sql .= substr($format, $vpos, $escpos – $vpos); //将%之间的字符串存入 $escpos++; //用来保存匹配到%的位置,这里加一用于下面的比较操作 $vpos = $escpos + 1; //$vpos的位置在$escpos的后一位 if($escpos == strlen($format)) //如果esc的位置等于$format的长度,则返回false,及%后无类型字符 {// % 后面没有类型字符 return false; } $vchar = $format{$escpos}; //$format中的第esc个字符 if($vchar != CDB::ESC) { if($argCount <= $argpos) {// 参数个数不够 return false; } $arg = $args[$argpos++]; } switch($vchar){ //判断%后的字符是什么,即我们要替换什么类型的数据 case CDB::NUM: $sql .= intval($arg); break; case CDB::STR: $sql .= $this->escape($arg); break; case CDB::RAW: $sql .= $arg; break; case CDB::ESC: $sql .= CDB::ESC; break; default: //非法的符号 return false; } } $rs = $this->query($sql); if(isbool($rs)) //判断最后结果的类型 { return $rs; } else { $r = array(); while( ($row = mysqlfetcharray($rs)) ) $r[] = $row; return $r; } } ?>

PHP数组:遍历过程中的改值操作

问题描述

前段时间写代码,需要在遍历数组的时候对数组中某些元素做修改。如果数组元素的键是顺序的整数,很简单,只要用for循环就可以了。如果是关联数组呢?首先想到的是foreach遍历数组。但是foreach虽然用来输出感觉很爽,但是修改数组内元素的时候,还多少是有那么点麻烦。和老段讨论后,老段提出了一种修改值的方法,我自己也想了几个办法。下面具体说一下:

引用操作符&

看下面这段代码中的$array数组,在foreach循环时对$value使用引用操作符,这样在循环中修改$value的值的时候,便将$array中对应的元素值修改了。

1, “B”=>1, “C”=>1, “D”=>1); foreach($array as &$value) $value = 2; print_r($array); ?>

上段代码的输出如下:

Array ( [A] => 2 [B] => 2 [C] => 2 [D] => 2 ) 

可以看到,$array中各个键对应的值都被修改成了2。看来这种方法确实奏效。

利用键值操作数组的元素

有的时候,数组中表示的可能是一些互相关联的元素,如果遇到了这些相互关联的元素中的一个,就将其他元素做一个标记的话,上面的引用肯定就不管用了。这时候修改这些关联元素的时候,就要使用其对应的键值了。先试试看管用不:

<?php $array = array(“A”=>1, “B”=>1, “C”=>1, “D”=>1); foreach($array as $key => $value){ if($key == “B”){ $array[“A”] = “CHANGE”; $array[“D”] = “CHANGE”; print_r($array); echo ‘
‘; }

if($value === "CHANGE")
    echo $value.'<br />';

} print_r($array); ?>

别着急看输出,我们想象中的应该是什么样呢?打印修改后的数组,打印一个“CHANGE”,再打印一遍修改后的数组。对吗?来看一下输出吧!

Array ( [A] => CHANGE [B] => 1 [C] => 1 [D] => CHANGE )
Array ( [A] => CHANGE [B] => 1 [C] => 1 [D] => CHANGE ) 

咦?怎么个情况?我们的CHANGE哪去了?

按照我们的想法,既然$array已经改变了,那么当遍历到键值为“D”的元素时,应当输出它的新值“CHANGE”才对!可是事实并不是我们想的那样。PHP在这里做了什么手脚呢?把上面的代码稍微修改一下。既然打印数组的时候,“D”=>CHANGE没错,那我们修改第二个if语句的判断条件:

<?php $array = array(“A”=>1, “B”=>1, “C”=>1, “D”=>1); foreach($array as $key => $value){ if($key == “B”){ $array[“A”] = “CHANGE”; $array[“D”] = “CHANGE”; print_r($array); echo ‘
‘; }

if($array[$key] === "CHANGE")
    echo $value.'<br />';

} print_r($array); ?>

猜猜它会输出什么?$value肯定不会等于“CHANGE”啦!难道等于1么?

Array ( [A] => CHANGE [B] => 1 [C] => 1 [D] => CHANGE )
1
Array ( [A] => CHANGE [B] => 1 [C] => 1 [D] => CHANGE ) 

那么,它确实就是1了。

这究竟是神马原因呢?翻到PHP文档的foreach那页,恍然:

Note: 除非数组是被引用,foreach 所操作的是指定数组的一个拷贝,而不是该数组本身。foreach对数组指针有些副作用。除非对其重置,在 foreach 循环中或循环后都不要依赖数组指针的值。

原来foreach所操作的是指定数组的一个拷贝。怪不得,取$value不管用了呢!理解到这里,上面的问题就解决了。只要在foreach中,直接按照键取$array中的元素进行各种判断赋值操作就可以了。

结语

好好看文档。

好好看文档。

好好看文档。

WordPress插件制作简介

第二次分享会详情

主讲人田大龙
题目WordPress插件开发
时间2011-4-24
 下载课件

————-华丽的分割线————-

这里并没有手把手教你制作一个插件出来,本篇文章意在向大家介绍WordPress插件制作的基本步骤以及需要了解的必要知识,详细的WP插件制作教程网上有很多,本文最后也推荐了一些比较好的教程网站。

OK,言归正传.

1:介绍

简单定义: WordPress插件是一个能够扩展WordPress博客功能的PHP脚本程序或函数集。 目的是为了使WordPress变得扩展性强,易修改和个性化。而且不需要修改WordPress的核心代码。

2:新建一个插件

2.1 名字,文件,位置

2.1.1 插件名 因为一个网站上可能会装很多个WordPress插件,所以要确保插件名字的唯一性。

2.1.2 插件文件 新建一个文件夹,将你插件的文件放入/wp-content/plugins/中,当然这个目录的名字也要唯一。

2.1.3 Readme 文件 无论是插件还是其他什么应用程序,README都是必不可少的。

2.1.4 主页

如果想制作一个较好的插件,最好为它设置一个主页,介绍关于插件的版本信息,使用说明等内容。

2.2 头信息

2.2.1 标准插件信息

需要在PHP头部插入标准的插件信息,WordPress才能识别你的插件。

形式如下:

[coolcode lang=”php”] /* Plugin Name: Name Of The Plugin Plugin URI: http://URIOfPageDescribingPluginandUpdates Description: A brief description of the Plugin. Version: The Plugin’s Version Number, e.g.: 1.0 Author: Name Of The Plugin Author Author URI: http://URIOfThePluginAuthor */ [/coolcode]

最主要的是Plugin Name,WordPress主要是识别它来显示出一个插件。

2.2.2 授权信息

通常大家就直接用标准的授权信息当作自己的授权信息。很多的插件用得就是GPL。加入下面的文字,

可以简要的说明GPL:

[coolcode lang=”php”]/* Copyright Glove glovenone@gmail.com */[/coolcode]

2.3 开始编程

2.3.1 WordPress插件钩子

API:Application Programming Interface 应用编程接口。

wordpress插件主要使用一种叫hook的接口:

A.动作 (Action): 动作是 WordPress 运行到某些环节,或者在某些事件发生时,就会被执行的一种钩子。比如说发表一篇文章、更换主题或者访问后台的某个管理界面,这些都是一件事件的例子。而插件则可以指定某些 PHP 函数来响应这些事件

使用动作来挂载插件的基本步骤如下:

在插件代码中定义当某个事件发生时,需要执行的 PHP 函数用add_action() 把这个函数注册到动作执行挂勾上把插件源码放到 WordPress 指定的地方,然后启用它

添加一个filter的格式为:

[coolcode lang=”php”]addaction ( ‘hookname’, ‘yourfunctionname’, [priority], [accepted_args] );[/coolcode]

例子:

当访客访问站点后,执行的是index.php,即WordPress的入口程序。index.php先后载入一些基本参数(如数据库信息、默认语言),进行一些必要的检查(如WordPress是否已经安装),然后载入我们的插件,当然,前提是这个插件已经启用。在插件中,我们输入以下代码:

[coolcode lang=”php”] function printmyfeed(){ //do something echo ‘Hello, boy!’; } addaction(‘wphead’,’printmyfeed’); [/coolcode]

如代码所示,wphead就是一个Action名,当WordPress执行到wphead这个Action时,它将执行我们插入的printmyfeed函数。这里的函数既可以做某些后台的操作,如update_option,也可以用于前台的输出,如echo,做一些适合在该Action发生的动作。

B.过滤器 (filter):是WordPress加载的,当文本被存入数据库或发送到浏览器之前,filter可用来对其进行多种类型的处理。使用filter,你的插件可以使用定义在其中的PHP函数来对文本进行多种处理。

添加一个filter的格式为:

[coolcode lang=”php”]addfilter(‘hookname’,’yourfilter’,[priority],[acceptedargs]);[/coolcode]

例子:

[coolcode lang=”php”] function addContent($content = “”) { //the content we modified $data = ‘the data we added’; $content .= $data; //add the data to the content originally return $content; } addfilter(“thecontent”, addContent); [/coolcode]

调用add_filter函数时,必须在数据显示、保存等操作之前进行.

2.3.2 保存插件数据到数据库

WordPress有多种方法将插件数据保存到数据表,我们既可以创建新的数据表,也可以用post_meta对单独文章、页面、附件等相关数据进行处理,也可以用“option”,这会是一个很常用的东西。

2.3.3 WordPress的option机制

WordPress有一套在数据库中保存、更改、读取独立的、有名字的数据(”options”)的机制,安装WP后,如果访问数据库,会发现里面有一个叫wp_option的数据表,它保存的内容就是有关我们博客的一些信息:地址,站点名称,文章属性等内容。我们可以通过调用option函数对数据库进行相关的添加、获取、更新等功能。

2.4  i18n你的插件
一个很有意思的词:i18n—internationalization,国际化的缩写,之所以如此缩写是因为从i到n有18个字母,它意指让我们的插件能够在世界上使用,即可以被翻译成各国语言。我们需要在定义字符串和输出字符串时做一些操作。

3:插件开发建议

  • 要遵循标准,统一标准可以给自己和他人同时带来方便,“WordPress Coding Stardards”。
  • 函数不要重名,否则可能会造成混乱,通常加一个不会重复的前缀就好了。
  • 代码中不要把WordPress前缀写成“wp_”,要写成$wpdb->prefix,虽然它们的意思相同。
  • 为了提高你插件的效率和可用性,尽量减少向数据写东西的次数,并且只“Select”你需要的字段。不要用“Select *”这样的语句,这种插件会让你WP的速度变慢很多。

4:相关资源

  1. wordpress官方API
  2. WordPress插件制作入门教程
  3. 自己动手写 WordPress 插件
  4. WordPress教程网 – WordPress插件的各种信息,也有关于wordpress其他的信息
  5. WordPress插件介绍
  6. 帕兰映像 – 不仅有WP的东西,是一个一个关于web的很不错的网站