2008年12月19日星期五

Joomla 入口

[text]
index.php -> Jsite(includes/application.php) -> JDocument <--> JHTML
[/text]

2008年12月12日星期五

清除浮动

[html]
<ul>
<li>
<p>test1</p>
<p>test2</p>
</li>
<li>
<p>test1</p>
<p>test2</p>
</li>
<li>
<p>test1</p>
<p>test2</p>
</li>
...
<br clear="all" />
</ul>
[/html]

ao
又是该死的 IE 问题
用 AJAX 返回的数据生成的用 UI/LI 结构的表格形式的代码
总是无法清除浮动
调试了N久后
才想到把页面最后生成的代码 alert出来
仔细一看才知道
本是在后面清楚浮动<br clear="all" />的却跑到前面去了
原来用 $("ul li:last").after(tmp) 增加的 HTML code 是加到 br 之后的~
为了通用
只能是判断浏览器
IE的话需再加上如下
[js]
$("ul li:last").append("<br clear="all" />");
[/js]

2008年12月2日星期二

PHP字符串经典函数

[php title="插入一段字符串"]
function str_insert($str, $i , $substr) {
for($j = 0 ; $j< $i; $j++){
$startstr .= $str[$j ];
}
for ($j = $i; $j < strlen($str); $j++){
$laststr .= $str[$j ];
}
$str = ($startstr . $substr . $laststr);
return $str ;
}
[/php]

[php title="删除一段字符串"]
function str_delete($str, $i, $j) {
for ($c = 0; $c < $i; $c++){
$startstr .= $str[$c];
}
for ($c = ($i + $j); $c < strlen($str); $c++) {
$laststr .= $str[$c];
}
$str = ($startstr . $laststr);
return $str;
}
[/php]

[php title="复制字符串"]
function strcpy($s1, $s2) {
if (strlen($s1) == null || !isset( $s2)) return;
for ($i = 0; $i < strlen($s1); $i++) {
$s2[] = $s1[$i];
}
return $s2;
}
[/php]

[php title="连接字符串"]
function strcat($s1, $s2) {
if (!isset($s1) || !isset( $s2)) return;
$newstr = $s1 ;
for($i = 0; $i < count($s); $i++){
$newstr .= $st[$i];
}
return $newsstr;
}
[/php]

[php title="简单编码函数 (与php_decode函数对应)"]
function php_encode($str) {
if ($str == '' && strlen($str) > 128) return false;
for($i = 0; $i < strlen($str); $i++) {
$c = ord($str[$i ]);
if ($c > 31 && $c < 107) $c += 20 ;
if ($c > 106 && $c < 127) $c -= 75 ;
$word = chr($c);
$s .= $word;
}
return $s;
}
[/php]

[php title="简单解码函数 (与php_encode函数对应)"]
function php_decode($str) {
if ($st r== '' && strlen($str) > 128) return false;
for( $i = 0; $i < strlen($str); $i++){
$c = ord($word);
if ( $c > 106 && $c < 127 ) $c = $c - 20;
if ($c > 31 && $c < 107) $c = $c + 75 ;
$word = chr($c);
$s .= $word ;
}
return $s;
}
[/php]

[php title="简单加密函数 (与php_decrypt函数对应)"]
function php_encrypt($str){
$encrypt_key = 'abcdefghijklmnopqrstuvwxyz1234567890';
$decrypt_key = 'ngzqtcobmuhelkpdawxfyivrsj2468021359';
if (strlen($str) == 0) return false;
for($i = 0; $i < strlen($str); $i++) {
for ($j=0; $j < strlen($encrypt_key); $j ++){
if ($str[$i] == $encrypt_key[$j]) {
$enstr .= $decrypt_key[$j];
break;
}
}
}
return $enstr;
}
[/php]

[php title="简单解密函数 (与php_encrypt函数对应)"]
function php_decrypt($str){
$encrypt_key = 'abcdefghijklmnopqrstuvwxyz1234567890';
$decrypt_key = 'ngzqtcobmuhelkpdawxfyivrsj2468021359';
if (strlen($str) == 0) return false;
for ($i = 0; $i < strlen($str); $i ++){
for ($j = 0; $j < strlen($decrypt_key); $j++) {
if ($str[$i] == $decrypt_key[$j]) {
$enstr .= $encrypt_key[$j];
break;
}
}
}

return $enstr;
}
[/php]

2008年11月11日星期二

PHP的HTTP认证机制

PHP 的 HTTP 认证机制仅在 PHP 以 Apache 模块方式运行时才有效,因此该功能不适用于 CGI 版本. 在 Apache 模块的 PHP 脚本中,可以用 header() 函数来向客户端浏览器发送 "Authentication Required" 信息,使其弹出一个用户名 / 密码输入窗口. 当用户输入用户名和密码后,包含有 URL 的 PHP 脚本将会加上 预定义变量 PHP_AUTH_USER , PHP_AUTH_PWAUTH_TYPE 被再次调用,这三个变量分别被设定为用户名,密码和认证类型. 预定义变量保存在 $_SERVER 或者 $HTTP_SERVER_VARS 数组中. 支持 "Basic" 和 "Digest" (自 PHP 5.1.0 起) 认证方法. 请参阅 header() 函数以获取更多信息.

PHP 版本问题: Autoglobals 全局变量,包括 $_SERVER 等,自 PHP 4.1.0 起有效, $HTTP_SERVER_VARS 从 PHP 3 开始有效.

以下是在页面上强迫客户端认证的脚本范例:
[php title="Basic HTTP 认证范例"]
if (!isset( $_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Text to send if user hits Cancel button';
exit;
} else {
echo "<p>Hello {$_SERVER ['PHP_AUTH_USER']} .</p>";
echo "<p>You entered { $_SERVER ['PHP_AUTH_PW']} as your password.</p>";
}
[/php]


本例演示怎样实现一个简单的 Digest HTTP 认证脚本. 更多信息请参考 RFC 2617 .
[php title="Digest HTTP 认证范例"]
$realm = 'Restricted area';

//user => password
$users = array('admin' => 'mypass', 'guest' => 'guest');

if (!isset($_SERVER ['PHP_AUTH_DIGEST'])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="' . $realm . '" qop="auth" nonce="' . uniqid (). '" opaque="' . md5 ( $realm ). '"');
die('Text to send if user hits Cancel button');
}

// analize the PHP_AUTH_DIGEST variable
preg_match('/username="(?P<username>.*)",
\s*realm="(?P<realm>.*)", \s*nonce="(?P<nonce>.*)",
\s*uri="(?P<uri>.*)", \s*response="(?P<response>.*)",
\s*opaque="(?P<opaque>.*)", \s*qop=(?P<qop>.*),
\s*nc=(?P<nc>.*), \s*cnonce="(?P<cnonce>.*)"/' ,
$_SERVER ['PHP_AUTH_DIGEST'], $digest
);

if (!isset($users[$digest['username']]))
die('Username not valid!' );


// generate the valid response
$A1 = md5($digest['username'] . ':' . $realm . ':' . $users[$digest['username']]);
$A2 = md5($_SERVER['REQUEST_METHOD']. ':' . $digest ['uri']);
$valid_response = md5 ($A1 . ':' . $digest['nonce']. ':' .
$digest['nc']. ':' .
$digest['cnonce']. ':' .
$digest['qop']. ':' . $A2
);

if ($digest['response'] != $valid_response)
die( 'Wrong Credentials!' );

// ok, valid username & password
echo 'Your are logged in as: ' . $digest [ 'username' ];
[/php]

兼容性问题: 在编写 HTTP 标头代码时请格外小心. 为了对所有的客户端保证兼容性,关键字 "Basic" 的第一个字母必须大写为 "B" ,分界字符串必须用双引号(不是单引号)引用;并且在标头行 HTTP/1.0 401 中,在 401 前必须有且仅有一个空格.

在以上例子中,仅仅只打印出了 PHP_AUTH_USERPHP_AUTH_PW 的值,但在实际运用中,可能需要对用户名和密码的合法性进行检查. 或许进行数据库的查询,或许从 dbm 文件中检索.

注意有些 Internet Explorer 浏览器本身有问题. 它对标头的顺序显得似乎有点吹毛求疵. 目前看来在发送 HTTP/1.0 401 之前先发送 WWW-Authenticate 标头似乎可以解决此问题.

自 PHP 4.3.0 起,为了防止有人通过编写脚本来从用传统外部机制认证的页面上获取密码,当外部认证对特定页面有效,并且安全模式 被开启时,PHP_AUTH 变量将不会被设置. 但无论如何, REMOTE_USER 可以被用来辨认外部认证的用户,因此可以用 $_SERVER['REMOTE_USER'] 变量.

配置说明: PHP 用是否有 AuthType 指令来判断外部认证机制是否有效.

注意,这仍然不能防止有人通过未认证的 URL 来从同一服务器上认证的 URL 上偷取密码.

Netscape Navigator 和 Internet Explorer 浏览器都会在收到 401 的服务端返回信息时清空所有的本地浏览器整个域的 Windows 认证缓存. 这能够有效的注销一个用户,并迫使他们重新输入他们的用户名和密码. 有些人用这种方法来使登录状态 "过期" ,或者作为 "注销" 按钮的响应行为.

[php title="强迫重新输入用户名和密码的 HTTP 认证的范例"]
function authenticate () {
header('WWW-Authenticate: Basic realm="Test Authentication System"');
header('HTTP/1.0 401 Unauthorized');
echo "You must enter a valid login ID and password to access this resource\n" ;
exit;
}

if (!isset($_SERVER[ 'PHP_AUTH_USER']) || ($_POST ['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER ['PHP_AUTH_USER'])) {
authenticate();
} else {
echo "<p>Welcome: {$_SERVER['PHP_AUTH_USER']} <br />";
echo "Old: { $_REQUEST['OldAuth']}" ;
echo "<form action='" . { $_SERVER ['PHP_SELF']} . "' METHOD='post'> \n " ;
echo "<input type=\"hidden\" name=\"SeenBefore\" value=\"1\" />\n" ;
echo "<input type=\"hidden\" name=\"OldAuth\" value=\"" . {$_SERVER ['PHP_AUTH_USER']} . \" /> \n " ;
echo "<input type=\"submit\" value=\"Re Authenticate\" />\n" ;
echo "</form></p>\n" ;
}
[/php]

该行为对于 HTTP 的 Basic 认证标准来说并不是必须的,因此不能依靠这种方法. 对 linux 浏览器的测试表明 linux 在收到 401 的服务端返回信息时不会清空认证文件,因此只要对认证文件的检查要求没有变化,只要用户点击 "后退" 按钮,再点击 "前进" 按钮,其原有资源仍然能够被访问. 不过,用户可以通过按 "_" 键来清空他们的认证信息.

同时请注意,在 PHP 4.3.3 之前,由于微软 IIS 的限制,HTTP 认证无法工作在 IIS 服务器的 CGI 模式下. 为了能够使其在 PHP 4.3.3 以上版本能够工作,需要编辑 IIS 的设置 "目录安全" . 点击 "编辑" 并且只选择 "匿名访问" ,其它所有的复选框都应该留空.

另一个限制是在 IIS 的 ISAPI 模式下使用 PHP 4 的时候,无法使用 PHP_AUTH_* 变量,而只能使用 HTTP_AUTHORIZATION . 例如,考虑如下代码:
[php]
list($user, $pw) = explode(':',
base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
[/php]

IIS 注意事项: 要 HTTP 认证能够在 IIS 下工作,PHP 配置选项 cgi.rfc2616_headers 必须设置成 0(默认值).

注: 如果安全模式被激活,脚本的 UID 会被加到 WWW-Authenticate 标头的 realm 部分.

2008年10月27日星期一

Javascript 遍历对象的属性和方法

[js]
function allProperties(obj) {

var properties = "";
//开始遍历
for(var p in obj){
if(typeof(obj[p])=="function"){
obj[p]();
} else {
properties += p + "=" + obj[p] + "\t";
}
}
alert(properties);
}
[/js]

2008年9月27日星期六

Javascript 面向对象介绍

FROM: JavaScript 面向对象的简单入门

如何创建对象


使用 constructor
[js]
var obj = new Object(); // var 可以省略
var obj = new Date();
[/js]
使用对象字面值(object literals)
[js]
var obj = "123" // 创建一个 String 对象
var obj = /^abc$/ //创建一个 RegExp 对象
[/js]

更加复杂的情况是, 我们可以直接生成一个自定义的只有属性的对象.
[js]
var obj = {
name : "test",
home : "Hunan Province China"
}
document.write(obj.name + "<br />")
document.write(obj.home)
[/js]
结果

killercat
Hunan Province China


JavaScript中的属性


[js]
str = "Hunan Province China" // str 一个字符串对象的引用
document.write(str.length)
[/js]
通过对象的引用加上.再加上属性名, 可以访问到这个属性, 也可以修改这个属性, 甚至是添加一个属性, 比如.
[js]
var obj = new Object()
obj.name = "test" // 为对象直接添加一个属性
document.write(obj.name) // 访问对象的属性
obj.name = "test1" // 修改对象的属性
document.write(obj.name)
[/js]

枚举属性值
使用 for ... in 语句可以枚举属性(具体来说就是枚举属性名)
[js]
for(ele in window){
document.write(ele + "<br />")
}
[/js]

如何得到属性值
[js]
obj = new Object()
obj.p1 = "a"
obj.p2 = "b"
obj.p3 = "c"
for(ele in obj)
document.write(obj.ele) // 这是新手可能犯的错误, obj.ele 的值是undefined
[/js]
应该这样访问属性值
[js]
document.write(eval("obj." + ele))
[/js]
未定义的属性:
[js]
obj = new Object()
document.write(obj.name)
[/js]
结果是

undefined


删除属性
[js]
obj = new Object()
obj.name = "killercat"
delete obj.name
document.write(obj.name)
[/js]
结果是

undefined


理解属性
在 Java, C++ 中, 属性要么属于某个类(类属性或说是静态属性), 要么属于对象, 也就是说, 同一个类的对象, 一定有一样的属性, 但是 JavaScript 不一样, 同样是 Object 的对象, 却可以有不同的属性. 除了这类的属性, JavaScript 中还有静态的属性(变量).

Constructor


源于某些未知原因, 有些人似乎不愿意在 JavaScript 提到 classes 这个词, 取代的是 对象的类型(object types), 甚至有些人直接叫函数, 于是可以看见这样的说法: "我们通过预先定义好的函数, 产生了一个对象". 本文使用类, 这个名词.
JavaScript 定义方法的方式和定义类的方式一模一样
[js]
function User(name,sex){ // 定义了类 User
this.name = name;
this.sex = sex;
}
user = new User("kc","man")
document.write(user.name + "<br />"+ user.sex)
[/js]
contructor 的作用就是在初始化属性(变量)

方法


以下例子引用于 JavaScript: The Definitive Guide
[js]
function Rectangle_area( ) { return this.width * this.height; }
function Rectangle_perimeter( ) { return 2*this.width + 2*this.height; }
function Rectangle_set_size(w,h) { this.width = w; this.height = h; }
function Rectangle_enlarge( ) { this.width *= 2; this.height *= 2; }
function Rectangle_shrink( ) { this.width /= 2; this.height /= 2; }
function Rectangle(w, h) {
this.width = w;
this.height = h;
this.area = Rectangle_area;
this.perimeter = Rectangle_perimeter;
this.set_size = Rectangle_set_size;
this.enlarge = Rectangle_enlarge;
this.shrink = Rectangle_shrink;
}
[/js]
这种风格可能和 Java, C++很不同. 方法中的 this 表示调用它的对象的引用.

prototype


prototype 是一个对象, 每个类都包含一个 prototype 对象(注意, 每个类一个, 而不是每个对象一个).
看看下面的例子
[js]
function User(name) {
this.name = name
}
User.prototype.name = "killercat" // 类名.prototype.属性(或方法)
user = new User("who" + "<br />")
document.write(user.name)
delete user.name
document.write(user.name)
[/js]
再看一个例子
[js]
function User(name) {
}
User.prototype.name = "human"
user1 = new User()
user2 = new User()
document.write(user1.name + "<br />")
document.write(user2.name)
[/js]
结果

human
human

说明每个类一个 prototype 对象, 而不是每个对象单独一个.
obj.x 这条语句的查找顺序是, 先在obj中找 x 属性, 假如没有, 再进入 obj 对应的类中找 prototype.x, 对于方法来说, 也一样. 因此, 不要出现这样的语句: user.prototype.name = "xxx" 必须是 user.name = "xxx" (prototype对象属于一个类, 而不是一个对象)
类名.prototype.属性 == 相当于一个实例变量(属性), 对方法也一样
类名.属性 == 相当于一个静态变量(属性), 对方法也一样, 调用的时候必须使用"类名.属性", 不能使用"类对象.属性", 因为它属于一个类, 而不是一个对象.
例如:
[js]
function User(name) {
this.name = name
}
User.type = "human"
user = new User("kc")
document.write(User.type + "<br />")
document.write(user.type)
[/js]
结果:

human
undefined

另外, 每个 prototype 都有一个 constructor 属性, 默认用于保存 constructor 的定义, 例如上面的 user 对象, 调用
user.constructor得到:
[js]
function User(name) { this.name = name; }
[/js]
我们可以通过 typeof, 知道参数的类型, 假如是对象, 就返回 object, 假如是方法就返回 function

利用 prototype 实现类间的继承


[js]
// 父类
function Circle(r) {
this.r = r;
}
Circle.PI = 3.14;
Circle.prototype.getArea = function (){
return Circle.PI * this.r * this.r;
};
Circle.prototype.toString = function (){
if(( typeof this == "object") && (this.constructor == Circle)){
return "circle with a radius " + this.r ;
} else {
return "unknown object";
}
};
Circle.max = function (c1,c2){
return c1.r >= c2.r ? c1 : c2;
};
// 子类
function ColorCircle(r,color){
this.r = r;
this.color = color;
}
ColorCircle.prototype = new Circle(0); // 保存父类的对象
ColorCircle.prototype.constructor = ColorCircle; // 为constructor 改名字
ColorCircle.prototype.toString = function(){
if(( typeof this == "object") && (this.constructor == ColorCircle)) {
return this.color+" circle with a radius " + this.r ;
} else {
return "unknown object";
}
}
ColorCircle.prototype.getColor = function(){
return this.color;
}
ColorCircle.prototype.setColor = function(color){
this.color = color;
}
[/js]
也就是, 使用 prototype 保存父类的对象, 在构造子类的时候, 父类对象同时被构造(因为 prototype 被构造). 也就是 JavaScript 继承其实就是让子类的 prototype 对象保存父类的对象.

2008年8月30日星期六

Javascript 函数


  1. 检测输入框不能为空

  2. 将一个变量转换为对象

  3. 判断是否大于某个数

  4. 判断是否小于某个数

  5. 判断是否是数字

  6. 判断是否是价格

  7. 判断是否是空

  8. 判断是否是空格

  9. 取得焦点

  10. 判断是否是整数

  11. 判断是否是日期

  12. 判断是否有有效数据被选中

  13. 检查是否是字符

  14. 检查是否是其它可以作名称的字符

  15. 检查是否是密码

  16. 检查是否是email

  17. 检查是否是邮编

  18. 检查是否是数字字符串

  19. 去掉字符串两边空格

  20. 判断一个字符串是否由数字(int or long)组成

  21. 判断一个字符串是否由数字(int or long or float)组成

  22. 判断一个字符串是否由数字或 '-','*' 组成

  23. 比较两个日期的大小

  24. 去掉字符串所有空格

  25. 转化日期

  26. 取得每月天数的函数

  27. 判断字符串由字符串和数字组成

  28. 判断一个字符串是否是由数字和"-"组成

  29. 弹出对话框



检测输入框不能为空

[js]
function doinputconnotempty(txtinput, minlength, salert){
txtinput.value = trim(txtinput.value);
var m_isvalid = true;
if(isempty(txtinput.value)) m_isvalid=false;
if(minlength > 0){
if(txtinput.value.length < minlength) m_isvalid=false;
}
if(!m_isvalid){
if(salert!="") window.alert(salert);
txtinput.focus();
}
return m_isvalid;
}
[/js]

将一个变量转换为对象

[js]
function var_to_obj(val) {
this.value=val;
}
[/js]
判断是否大于某个数

[js]
function is_greater(field,crit,limit) {
var ret = (is_numeric(field,-1) ) ? (field.value > limit ) : false;
if (!ret)
docritcode(field,crit,"value must be greater than "+limit);
return(ret);
}
[/js]

判断是否小于某个数

[js]
function is_less(field,crit,limit) {
var ret = (is_numeric(field,-1) ) ? (field.value < limit ) : false;
if (!ret)
docritcode(field,crit,"value must be less than "+limit);
return(ret);
}
[/js]

判断是否是数字

[js]
function is_numeric(field,crit,msg) {
var ret = true;
var numstr="0123456789";
var decused=false;
var chr;
for (i = 0;i < field.value.length; ++i ) {
chr=field.value.charat(i);
if (numstr.indexof(chr,0)==-1) {
if ( (!decused) && chr==".") {
decused=true;
} else {
ret=false;
}
}
}
if (!ret)
docritcode(field,crit,msg);
return(ret);
}
[/js]

判断是否是价格

[js]
function is_price(field,crit,msg) {
var ret = true;
var numstr="0123456789";
var decused=false;
var chr;
for (i=0;i < field.value.length; ++i) {
chr=field.value.charat(i);
if (numstr.indexof(chr,0) == -1) {
if ( (!decused) && chr==".") {
decused=true;
} else {
ret=false;
}
}
}
if(ret) {
if(decused&&(field.value.length-field.value.indexof('.') < 4));
else if(decused)
ret=false;
}
if (!ret)
docritcode(field,crit,msg);
return(ret);
}
[/js]

判断是否是空

[js]
function is_null(field,crit,msg) {
var text=""+ trim(field.value);
if(text.length) {
for(var i = 0;i < text.length; i++)
if(text.charat(i)!=" "&&text.charat(i)!=" ")
break;
if(i>=text.length) {
ret=true;
} else {
ret=false;
}
} else
ret=true;

if (ret)
docritcode(field,crit,msg);
return(ret);
}
[/js]

判断是否是空格

[js]
function isspace(field) {
var text=""+field.value;
if(text.length) {
for(var i = 0;i < text.length; i++ )
if ( text.charat(i) != " " && text.charat(i) != " ")
break;
if( i > = text.length)
field.value="";
}
}
[/js]

取得焦点

[js]
function docritcode(field,crit,msg) {
if ( (-1!=crit) ) {
alert(msg)
if (crit==1) {
field.focus(); // focus does not work on certain netscape versions
field.select();
}
}
}
[/js]

判断是否是整数

[js]
function is_int(field,crit,msg){
var ret = true;
var numstr="0123456789";
var chr;
if (field.value.length==0){
ret=false;
}
for (i = 0;i < field.value.length; ++i) {
chr=field.value.charat(i);
if (numstr.indexof(chr,0)==-1){
ret=false;
}
}
if (!ret)
docritcode(field,crit,msg);
return(ret);
}
[/js]

判断是否是日期

[js]
function is_date(field,crit,msg) {
var ret = false;
var mark1;
var mark2;
var days;
var y;
var m;
var d;
if(field.value=="")
return true;
cd=new date();

if ( (mark1 = field.value.indexof('-'))==-1)
mark1=field.value.indexof('-');

if (mark1 > -1) {
if ( (mark2 = field.value.indexof('-',mark1+1)) ==-1)
mark2=field.value.indexof('-',mark1+1);
if ((mark2 > -1)&&(mark2+1 < field.value.length) ) {
y = parseint(field.value.substring(0,mark1),10);
m = parseint(field.value.substring(mark1+1,mark2),10);
d = parseint(field.value.substring(mark2+1,field.value.length),10);

year = new var_to_obj(y);
month = new var_to_obj(m);
day = new var_to_obj(d);
days = getdaysinmonth(month.value,year.value) + 1;

if (
(is_greater(day,-1,0))&&(is_less(day,-1,days))&&
(is_greater(month,-1,0))&&(is_less(month,-1,13))&&
(is_greater(year,-1,1900))&&(is_less(year,-1,2500))
)
ret=true;
}
}
if (!ret) docritcode(field,crit,msg);

return(ret);
}
[/js]

判断是否有有效数据被选中

[js]
function isselected(field,crit,msg) {
value=""+field.options[field.selectedindex].value;
if(value=="0")
ret=false;
else
ret=true;
if (!ret)
docrit(field,crit,msg);
return(ret);
}
[/js]

检查是否是字符

[js]
function ischaracter( ccharacter ) {
var sformat = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";

if( sformat.indexof( ccharacter, 0 ) == -1 ) {
return false;
}

return true;
}
[/js]

判断是否是数字和字母的组合

[js]
function ischrandnum( ccharacter ) {
for(ilen=0;ilen < str.length; ilen++) {
if(str.charat(ilen) < '0' || str.charat(ilen) > '9' ) {
if(str.charat(ilen) < 'a' || str.charat(ilen) > 'z' ) {
if(str.charat(ilen) < 'a' || str.charat(ilen) > 'z' )
return false;
}
}
}
return true;
}
[/js]

检查是否是其它可以作名称的字符

[js]
function isothernamecharacter( ccharacter ){
var sformat = "_";

if( sformat.indexof( ccharacter, 0 ) == -1 ) {
return false;
}

return true;
}

function isothernamecharacter1( ccharacter ) {
var sformat = "-";

if( sformat.indexof( ccharacter, 0 ) == -1 ) {
return false;
}

return true;
}

function isothernamecharacter2( ccharacter ) {
var sformat = ".";

if( sformat.indexof( ccharacter, 0 ) == -1 ){
return false;
}

return true;
}

// 检查是否是可以作名称的字符
// svalue: 输入值
function isnamecharacter( svalue ) {
if( svalue == null ) {
return false;
}

for( i = 0; i < svalue.length; i ++ ) {
var ccharacter = svalue.charat( i );
if( isdigital( ccharacter ) == false && ischaracter( ccharacter ) == false && isothernamecharacter( ccharacter ) == false&& isothernamecharacter1( ccharacter ) == false&& isothernamecharacter2( ccharacter ) == false ) {
return false;
}
}

return true;
}
[/js]

检查是否是密码

[js]
function ispassword( svalue ) {
if( svalue == null ) {
return false;
}

for( i = 0; i < svalue.length; i ++ ) {
var ccharacter = svalue.charat( i );
if( isdigital( ccharacter ) == false && ischaracter( ccharacter ) == false && isothernamecharacter( ccharacter ) == false) {
return false;
}
}

return true;
}
[/js]

检查是否是email

[js]
// svalue: 输入值, 合法格式为a@b.c.d此类形式
function isemail( svalue ) {
var ifirstindex = 0;
var isecondindex = svalue.indexof( '@' );
if( isecondindex == -1 ){
return false;
}

var stemp = svalue.substring( ifirstindex, isecondindex );
if( isnamecharacter( stemp ) == false ) {
return false;
}

isecondindex = svalue.indexof( '.' );
if( isecondindex == -1 || svalue.substring( svalue.length-1, svalue.length ) == '.' ) {
return false;
} else if( stemp.length == svalue.length - 2 ) {
// the last two characters are '@' and '.'
return false;
} else{
var stempvalue = svalue;
isecondindex = svalue.indexof( '@' );
while( isecondindex != -1 ) {
ifirstindex = isecondindex + 1;
stempvalue = stempvalue.substring( ifirstindex, stempvalue.length ); // the right section of value
isecondindex = stempvalue.indexof( '.' );
//document.write( "stempvalue=" + stempvalue + "<br>" );
stemp = stempvalue.substring( 0, isecondindex );
//document.write( "stemp=" + stemp + "<br>" );
if( isnamecharacter( stemp ) == false ) {
return false;
}
}

if( isnamecharacter( stempvalue ) == false ){
return false;
}
}

return true;
}
[/js]

检查是否是邮编

[js]
// svalue: 输入值, 合法格式为六位整数
function iszip( svalue ) {
if( svalue == null ) {
return false;
}

if( svalue.length != 6 ) {
return false;
} else {
for( i = 0; i < 6; i ++ ) {
if( isdigital( svalue.charat( i ) ) == false ) {
return false;
}
}
}

return true;
}
[/js]

检查是否是数字字符串

[js]
// svalue: 输入值
function isdigitalstring( svalue ) {
if( svalue == null ) {
return false;
}

for( i = 0; i < svalue.length; i ++ ) {
if( isdigital( svalue.charat( i ) ) == false ) {
return false;
}
}
}
[/js]

判断一个字符串是否为空

[js]
function isempty(his) {
flag = true;
for(var i=0;i < his.length;i++) {
if(his.charat(i)!=" ") {
flag = false;
break;
}
}
return flag;
}
[/js]

去掉字符串两边空格

[js]
function trim(his) {
//找到字符串开始位置
pos_start = -1;
for(var i=0;i < his.length;i++) {
if(his.charat(i)!=" ") {
pos_start = i;
break;
}
}
//找到字符串结束位置
pos_end = -1;
for(var i=his.length-1;i>=0;i--) {
if(his.charat(i)!=" "){
pos_end = i;
break;
}
}
//返回的字符串
str_return = ""
if(pos_start!=-1 && pos_end!=-1){
for(var i=pos_start;i<=pos_end;i++) {
str_return = str_return + his.charat(i);
}
}
return str_return;
}
[/js]

判断一个字符串是否由数字(int or long)组成

[js]
function isdigital(str) {
for(ilen=0;ilen < str.length;ilen++) {
if(str.charat(ilen) < '0' || str.charat(ilen) > '9' ) {
return false;
}
}
return true;
}
[/js]

判断一个字符串是否由数字(int or long or float)组成

[js]
function isfloat(str) {
flag_dec = 0
for(ilen=0;ilen < str.length;ilen++) {
if(str.charat(ilen) == '.') {
flag_dec++;
if(flag_dec > 1)
return false;
else
continue;
}
if(str.charat(ilen) < '0' || str.charat(ilen) > '9' ) {
return false;
}
}
return true;
}
[/js]

判断一个字符串是否由数字或'-','*'组成

[js]
function istelephone(str) {
for(ilen=0;ilen < str.length;ilen++){
if(str.charat(ilen) < '0' || str.charat(ilen) > '9' ){
if((str.charat(ilen)!='-')&&(str.charat(ilen)!='*'))
return false;
}
}
return true;
}
[/js]

比较两个日期的大小

[js]
//num1>num2 return:true;num1<=num2 return:false
function compare_date(num1,num2) {
var pos1,pos2,end;
var para1,para2,para3,para4,para5,para6;

//para1:年
//para2:月
//para3:日
end=num1.length;
pos1=num1.indexof("-",0);
pos2=num1.indexof("-",pos1+1);
para1=num1.substring(0,pos1);
para2=num1.substring(pos1+1,pos2);
para3=num1.substring(pos2+1,end);
para1=parseint(para1,10);
para2=parseint(para2,10);
para3=parseint(para3,10);
end=num2.length;
pos1=num2.indexof("-",0);
pos2=num2.indexof("-",pos1+1);
para4=num2.substring(0,pos1);
para5=num2.substring(pos1+1,pos2);
para6=num2.substring(pos2+1,end);
para4=parseint(para4,10);
para5=parseint(para5,10);
para6=parseint(para6,10);
if(para1>para4) {
return true;
} else if(para1==para4) {
if(para2>para5) {
return true;
} else if(para2==para5) {
if(para3>para6) {
return true;
}
}
}
return false;
}
[/js]

去掉字符串所有空格

[js]
function jtrimstr(str) {
var i=0;
var j;
var len=str.length;
trimstr="";
while(i < len) {
if(str.charat(i)!=" ") {
trimstr=trimstr+str.charat(i);
}
i++;
}
return(trimstr);
}
[/js]

转化日期

[js]
function transferdate(str) {
var m=4;
var strlen=str.length
var n=strlen-1;
while (n>=strlen-2) {
if(str.charat(n)=="-") {
break;
}
n=n-1
}
trimstr=str.substring(m+1,n)+"/"+ str.substring(n+1,strlen)+"/"+str.substring(0,m)
return(trimstr)
}
[/js]

取得每月天数的函数

[js]
//1.取得每月天数的函数
//参数说明: month--月;year--年
// 返回值: days--天数
function getdaysinmonth(month,year) {
var days;
if (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) days=31;
else if (month==4 || month==6 || month==9 || month==11) days=30;
else if (month==2) {
if (isleapyear(year)) { days=29; }
else { days=28; }
}
return (days);
}
//2.判断是否为润年的函数
//参数说明: year -- 年份
// 返回值: 如果是润年, 返回true; 否则返回false.

function isleapyear (year) {
if (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0)) {
return (true);
} else {
return (false);
}
}
[/js]


判断字符串由字符串和数字组成

[js]
function ischarsf(str) {
for(ilen=0;ilen < str.length;ilen++) {
if(str.charat(ilen) < '0' || str.charat(ilen) > '9' ) {
if(str.charat(ilen) < 'a' || str.charat(ilen) > 'z' )
return false;
}
}
return true;
}
[/js]

判断一个字符串是否是由数字和"-"组成

[js]
function ismonth(str) {
for(ilen=0;ilen < str.length;ilen++){
if(str.charat(ilen) < '0' || str.charat(ilen) > '9' ) {
if((str.charat(ilen)!='-'))
return false;
}
}
return true;
}
[/js]

弹出对话框

[js]
function popmodaldialog(url,args,height,width){
return window.showmodaldialog(url,args,"dialogheight:"+height+"px;dialogwidth:"+width+"px;center:yes;help:no;resizable:no;status:no;");
}
[/js]

2008年8月9日星期六

header 常用指令

header 分为三部分:

  • 第一部分为HTTP协议的版本(HTTP-Version)

  • 第二部分为状态代码(Status)

  • 第三部分为原因短语(Reason-Phrase)




fix 404 pages: 用这个 header 指令来解决 URL 重写产生的 404 header
[php]
header('HTTP/1.1 200 OK');
[/php]

set 404 header: 页面没找到
[php]
header('HTTP/1.1 404 Not Found');
[/php]

set Moved Permanently header (good for redrictions), use with location heade : 页面被永久删除,可以告诉搜索引擎更新它们的 urls
[php]
header('HTTP/1.1 301 Moved Permanently');
[/php]

访问受限
[php]
header('HTTP/1.1 403 Forbidden');
[/php]

服务器错误
[php]
header('HTTP/1.1 500 Internal Server Error');
[/php]

redirect to a new location: 重定向到一个新的位置
[php]
header('Location: http://www.google.com);
[/php]


redrict with delay: 延迟一段时间后重定向
[php]
header('Refresh: 10; url=http://www.sina.com.cn');
print 'You will be redirected in 10 seconds';
[/php]


override X-Powered-By: PHP: 覆盖 X-Powered-By value
[php]
header('X-Powered-By: PHP/4.4.0');
[/php]


content language (en = English): 内容语言 (en = English)
[php]
header('Content-language: en');
[/php]

last modified (good for caching): 最后修改时间 (在缓存的时候可以用到)
[php]
$time = time() - 60; // or filemtime($fn), etc
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $time).' GMT');
[/php]

header for telling the browser that the content did not get changed: 告诉浏览器要获取的内容还没有更新
[php]
header('HTTP/1.1 304 Not Modified');
[/php]

set content length (good for caching): 设置内容的长度 (缓存的时候可以用到):
[php]
header('Content-Length: 1234');
[/php]

headers for an download: 用来下载文件
[php]
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="example.zip"');
header('Content-Transfer-Encoding: binary');
[/php]


disable caching of the current document: 禁止缓存当前文档
[php]
header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
[/php]


设置内容类型
[php]
header('Content-Type: text/html; charset=utf-8');
[/php]


plain text file
[php]
header('Content-Type: text/plain');
[/php]

JPG picture
[php]
header('Content-Type: image/jpeg');
[/php]

ZIP file
[php]
header('Content-Type: application/zip');
[/php]

PDF file
[php]
header('Content-Type: application/pdf');
[/php]

Audio MPEG (MP3,...) file
[php]
header('Content-Type: audio/mpeg');
[/php]

Flash animation
[php]
header('Content-Type: application/x-shockwave-flash');
[/php]

显示登录对话框,可以用来进行 HTTP 认证
[php]
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Basic realm="Top Secret"');
print 'Text that will be displayed if the user hits cancel or enters wrong login';
[/php]

表单填写时,可用 AJAX 对用户随时进行验证、提示,但是在用户没有留意 AJAX 提交了错误表单的提示信息时, ,跳回原页,而填写的信息全部丢失。要支持页面回跳,有以下的办法:

  • 使用 session_cache_limiter 方法: session_cache_limiter('private,must-revalidate');,但是要值得注意的是 session_cache_limiter() 方法要写在 session_start() 方法之前才有用。

  • 用header来设置控制缓存的方法: header('Cache-control:private,must-revalidate')

2008年7月27日星期日

CSS 浮动清理

在进行浮动布局时,大多数人都深知,在必要的地方进行浮动清理:<div style="clear:both;"></div>。
例如:
<div style="background:#666;"> <!-- float container -->
<div style="float:left; width:30%; height:40px;background:#EEE; ">Some Content</div>
</div>
此时预览此代码,我们会发现最外层的父元素float container,并没有显示。这是因为子元素因进行了浮动,而脱离了文档流,导致父元素的height为零。
若将代码修改为:
<div style="background:#666;"> <!-- float container -->
<div style="float:left; width:30%; height:40px;background:#EEE; ">Some Content</div>
<div style="clear:both"></div>
</div>
注意,多了一段清理浮动的代码。这是一种好的CSS代码习惯,但是这种方法增加了无用的元素。这里有一种更好的方法,将HTML代码修改为:
<div class="clearfix" style="background:#666;"> <!-- float container -->
<div style="float:left; width:30%; height:40px;background:#EEE; ">Some Content</div>
</div>
定义CSS类,进行“浮动清理”的控制:
.clearfix:after {
content: ".";
clear: both;
height: 0;
visibility: hidden;
display: block;
} /* 这是对Firefox进行的处理,因为Firefox支持生成元素,而IE所有版本都不支持生成元素 */
.clearfix {
display: inline-block;
} /* 这是对 Mac 上的IE浏览器进行的处理 */
/* Hides from IE-mac \*/
* html .clearfix {height: 1%;} /* 这是对 win 上的IE浏览器进行的处理 */
.clearfix {display: block;} /* 这是对display: inline-block;进行的修改,重置为区块元素*/
/* End hide from IE-mac */

2008年7月8日星期二

Cache-Control, Expires

FROM: “Cache-control”常见的取值有private、no-cache、max-age、must-revalidate等

Cache-Control


网页的缓存是由 HTTP 消息头中的 Cache-Control 来控制的,常见的取值有 privateno-cachemax-agemust-revalidate等,默认为 private。其作用根据浏览方式不同分为以下几种情况:

打开新窗口

值为 privateno-cachemust-revalidate时,打开新窗口访问时都会重新访问服务器。而如果指定了 max-age 值,那么在此值内的时间里就不会重新访问服务器,例如:Cache-Control: max-age=5 (表示当访问此网页后的 5 秒内再次访问不会去服务器)

在地址栏回车


  • privatemust-revalidate 只有第一次访问时会访问服务器,以后就不再访问。

  • no-cache 每次都会访问。

  • max-age 则在过期之前不会重复访问。



按后退按扭


  • privatemust-revalidatemax-age 不会重访问。

  • no-cache 每次都重复访问。




按刷新按扭

无论为何值,都会重复访问。

Cache-Control 值为 no-cache 时,访问的页面不会在 IE 临时文件夹中留下页面备份 (Firefox、Chrome 会留下)。

另外,通过指定 Expires 值也会影响到缓存。例如,指定 Expires 值为一个过去的时间,那么访问此网时若重复在地址栏按回车,那么每次都会重复访问。

Expires


如果服务器上的网页经常变化,把 Expires 设置为 -1,表示立即过期。如果一个网页每天凌晨 1 点更新,可以把 Expires 设置为第二天的凌晨 1 点。

当 HTTP1.1 服务器指定 CacheControl: no-cache 时,浏览器就不会缓存该网页。HTTP 1.0 服务器不能使用 Cache-Control。所以为了向后兼容 HTTP 1.0 服务器,IE 使用 Pragma: no-cache 以对 HTTP 1.0 提供特殊支持。

如果客户端通过安全连接 (与服务器通讯,且服务器在响应中返回 Pragma:no-cache,则 IE不会缓存此响应。注意: Pragma:no-cache 仅当在安全连接中使用时才防止缓存,如果在非安全页中使用,处理方式与 Expires:-1 相同,该页将被缓存,但被标记为立即过期。

禁止页面在 IE 中缓存,header 响应消息头部设置:
[html]
CacheControl: no-cache
Pragma: no-cache
Expires: -1
[/html]

2008年6月27日星期五

Apache加载不同版本的PHP

php version is lower than 5, use php5 function, add this sentence to .htaccess file, the condition, it has installed php5 at the same time.
.htaccess file content as below:
use apacheAddHandler application/x-httpd-php5 .php .php4 .php3 .phtml

2008年5月27日星期二

CSS hack

#left { color:#000;} FF
*html #left {color:#333;} IE6
*+html #left {color:#ccc;} IE7


#main {
width:750px;
padding:0px !important!;
padding:5px;
}
!important 作用是提示指定样式规则的应用优先权,IE不支持的值。

.test {
color:#000; //FF
*color:#333; //IE系列
_color:#ccc; //IE6
}

2008年5月2日星期五

MySQL 源码安装

[bash]
groupadd mysql
useradd -g mysql mysql
tar zxvf mysql-*.**.**.tar.gz
cd mysql-*.**.**
./configure --prefix=/usr/local/mysql
make
make install
scripts/mysql_install_db
chown -r root /usr/local/mysql
chown -r mysql /usr/local/mysql/var
chgrp -r mysql /usr/local/mysql
cp support-files/my-medium.cnf /etc/my.cnf
cp scripts /usr/local/mysql -r
cp support-files /usr/local/mysql -r
cd /usr/local/mysql
chmod +x support-files/mysql.server
cp support-files/mysql.server /etc/rc.d/init.d/mysqld
[/bash]

设置 MySQL 开机自动运行:
[bash]
ln -s /etc/rc.d/init.d/mysqld /etc/rc.d/rc3.d/mysqld
echo "/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf &" >> /etc/rc.d/rc.local
/etc/rc.d/init.d/mysqld start
[/bash]

MySQL 客户端
[bash]
/usr/local/mysql/bin/mysqladmin -u root -p
[/bash]


TIPS: 忘记密码时启动
[bash]
safe_mysqld --skip-grant-tables
[/bash]

2008年4月7日星期一

Cronjob

Cron 是UNIX, SOLARIS,LINUX下的一个十分有用的工具。通过Cron脚本能使计划任务定期地在系统后台自动运行。这种计划任务在UNIX, SOLARIS, LINUX下术语为cron jobs。 Crontab ( cron 表)则是用来记录在特定时间运行的 cron 的一个脚本文件。

Crontab归结为以下几点特性:
A. Crontab约束
当用户名记录在文件/usr/lib/cron/cron.allow时,该用户的crontab有效。当/usr/lib/cron /cron.allow 文件不存在时,用户名没被记录在/usr/lib/cron/cron.deny文件中,该用户的crontab也有效。当只存在/usr/lib /cron/cron.deny且为空时,所有的用户都可使用crontab。当前两个文件都不存在时,只有root用户可以使用crontab。 Deny或allow记录以每行一个用户名的形式记录信息。

B. Crontab 命令

  • export EDITOR=vi 为crontab文件指定一个编辑器

  • crontab -e 编辑该用户的crontab,当指定crontab 不存在时新建。

  • crontab -l 列出该用户的crontab

  • crontab -r 删除该用户的crontab

  • crontab -u<用户名称> 指定要设定crontab的用户名称

  • crontab –v 显示上一次编辑的时间(只在某些操作系统上可用)



C. Crontab 文件
Crontab语法一个crontab文件用五个段来定义:分,小时,天,月份和周日,和一个要定期执行的命令代码。
[text]
* * * * * command to be executed
- - - - -
| | | | |
| | | | +----- day of week (0 - 6) (Sunday=0)
| | | +------- month (1 - 12)
| | +--------- day of month (1 - 31)
| +----------- hour (0 - 23)
+------------- min (0 - 59)
[/text]

所有的值都必须在相应的范围之内,否则视为无效。在填值区域内可以是 * 也可以是以 , 分隔的一组值。值可以是一个数据也可以是用连接符连起来的两个数(表示范围)。
注:日期的格式可以是星期,也可以是一个月中的天。假如两个都有值,则在这两个时间都会执行。

D. Crontab 实例
下面是crontab文件中的一行,意思是在每天下午6:30中删除临时文件(临时文件存放在/home/someuser/tmp)。
[bash]
30 18 * * * rm /home/someuser/tmp/*
[/bash]
以下我们改变参数的值使其在不同的时间运行:如下表







































min hour day/month month day/week Execution time
30 0 1 1,6,12 * --00:30 on 1st of Jan,June & Dec
0 20 * 10 1-5 --8:00 PM every weekday(Mon-Fir) only in Oct
0 0 1,10,15 * * --midnight on 1st,10th & 15th of month
5,10 0 10 * 1 --At 12:05 12:10 every Monday & on 10th of every month


注:要是无意间键入了没带参数的crontab 命令,别 Control-d 退出,这样会删掉所有的cronjob。 应该 Control -c 退出.
在以上任何值中,星号 * 可以用来代表所有有效的值。譬如:月份值中的星号意味着在满足其它制约条件后每月都执行该命令。
整数间的短线 - 指定一个整数范围。譬如,1-4 意味着整数 1、2、3、4。
用逗号 , 隔开的一系列值指定一个列表。譬如,3, 4, 6, 8 标明这四个指定的整数。
正斜线 / 可以用来指定间隔频率。在范围后加上 / 意味着在范围内可以跳过 integer。譬如,0-59/2 可以用来在分钟字段定义每两分钟。间隔频率值还可以和星号一起使用。例如,*/3 的值可以用在月份字段中表示每三个月运行一次任务。
开头为井号# 的行是注释,不会被处理。

E. Crontab 环境设置
Cron其实是在shell(/usr/bin/sh).后台引用用户程序的命令。
Cron默认的shell环境是:
[bash]
HOME=user's-home-directory
LOGNAME=user's-login-id
PATH=/usr/bin:/usr/sbin:
SHELL=/usr/bin/sh
[/bash]
用户希望自己的配置文件在表或者脚本的入口直接执行。

F. 禁用邮件默认的cronjobs在执行任务时会给用户发一封邮件。如果您不需要的话可以通过以下命令关闭。 >/dev/null 2>&1

H. 生成日志文件保存cronjobs日志只需作如下设置就可以
[bash]
30 18 * * * rm /home/someuser/tmp/* > /home/someuser/cronlogs/clean_tmp_dir.log
[/bash]
/home/someuser/cronlogs/clean_tmp_dir.log 为日志文件保存的绝对路径


常用的crontab命令:

  • crontab -l 显示所有现存cron job.

  • crontab -r 删除当前cron jobs.

  • crontab -e 编辑当前 crontab file.

    编辑/etc/crontab 文件配置 cron
    cron服务每分钟不仅要读一次/var/spool /cron内的所有文件,还需要读一次/etc/crontab,因此配置这个文件也能运用 cron服务做一些事情。用crontab配置是针对某个用户的,而编辑/etc/crontab是针对系统的任务。此文件的文件格式是:
    [bash]
    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root #如果出现错误,或者有数据输出,数据作为邮件发给这个帐号
    HOME=/
    # run-parts
    01 * * * * root run-parts /etc/cron.hourly #每个小时去执行一遍/etc/cron.hourly内的脚本
    02 4 * * * root run-parts /etc/cron.daily #每天去执行一遍/etc/cron.daily内的脚本
    22 4 * * 0 root run-parts /etc/cron.weekly #每星期去执行一遍/etc/cron.weekly内的脚本
    42 4 1 * * root run-parts /etc/cron.monthly #每个月去执行一遍/etc/cron.monthly内的脚本
    [/bash]

    注意: run-parts,如果去掉这个参数的话,后面就可以写要运行的某个脚本名,而不是文件夹名。root 表示运行该命令的用户名。

    看下面的内容:
    cron 是一个可以用来根据时间、日期、月份、星期的组合来调度对重复任务的执行的守护进程。
    cron 假定系统持续运行。如果当某任务被调度时系统不在运行,该任务就不会被执行。
    要使用 cron 服务,必须安装了 vixie-cron RPM 软件包,而且必须在运行 crond 服务。要判定该软件包是否已安装,使用 rpm -q vixie-cron 命令。要判定该服务是否在运行,使用 /sbin/service crond status 命令。

    cron 的主配置文件是 /etc/crontab,它包括下面几行:
    [bash]
    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    HOME=/

    # run-parts
    01 * * * * root run-parts /etc/cron.hourly
    02 4 * * * root run-parts /etc/cron.daily
    22 4 * * 0 root run-parts /etc/cron.weekly
    42 4 1 * * root run-parts /etc/cron.monthly
    [/bash]

    前四行是用来配置 cron 任务运行环境的变量。 SHELL 变量的值告诉系统要使用哪个 shell 环境(在这个例子里是 bash shell), PATH 变量定义用来执行命令的路径。cron 任务的输出被邮寄给 mailto 变量定义的用户名。如果 mailto 变量被定义为空白字符串 (mailto=" "),电子邮件就不会被寄出。HOME 变量可以用来设置在执行命令或脚本时使用的主目录。

    /etc/crontab 文件中的每一行都代表一项任务。

    如果某 cron 任务需要根据调度来执行,而不是每小时、每日、每周、或每月地执行,它可以被添加到 /etc/cron.d 目录中。该目录中的所有文件使用和 /etc/crontab 中一样的语法。如下:
    [bash]
    #record the memory usage of the system every monday at 3:30AM in the file /tmp/meminfo
    30 3 * * mon cat /proc/meminfo >> /tmp/meminfo
    #run custom script the first day of every month at 4:10AM
    10 4 1 * * /root/scripts/backup.sh
    [/bash]

    根用户以外的用户可以使用 crontab 工具来配置 cron 任务。所有用户定义的 crontab 都被保存在 /var/spool/cron 目录中,并使用创建它们的用户身份来执行。要以某用户身份创建一个 crontab 项目,登录为该用户,然后键入 crontab -e 命令,使用由 VISUAL 或 EDITOR 环境变量指定的编辑器来编辑该用户的 crontab。该文件使用的格式和 /etc/crontab 相同。当对 crontab 所做的改变被保存后,该 crontab 文件就会根据该用户名被保存,并写入文件 /var/spool/cron/username 中。

    cron 守护进程每分钟都检查 /etc/crontab 文件、etc/cron.d/ 目录、以及 /var/spool/cron 目录中的改变。如果发现了改变,它们就会被载入内存。这样,当某个 crontab 文件改变后就不必重新启动守护进程了。

    /etc/cron.allow 和 /etc/cron.deny 文件被用来限制对 cron 的使用。这两个使用控制文件的格式都是每行一个用户。两个文件都不允许空格。如果使用控制文件被修改了,cron 守护进程 (crond) 不必被重启。使用控制文件在每次用户添加或删除一项 cron 任务时都会被读取。

    无论使用控制文件中的规定如何,根用户都总是可以使用 cron。
    如果 cron.allow 文件存在,只有其中列出的用户才被允许使用 cron,并且 cron.deny 文件会被忽略。
    如果 cron.allow 文件不存在,所有在 cron.deny 中列出的用户都被禁止使用 cron。

    • /sbin/service crond start 启动 cron 服务,推荐在引导时启动该服务

    • /sbin/service crond stop 停止 cron 服务



    增加 cron 的工作
    当决定要在系统上定期执行某个命令,必须将这个要执行的命令定义成一个 cron 工作,可以直接将要建立的 cron 工作定义在 cron TAB设置文件中,设置该命令执行的时机;或者也可以利用 cron 会定时执行 /etc/cron.*目录 scripts 的特性,将要执行的命令建立成为一个脚本文档,放置在该目录下,并且注意它的权限必须可以执行.

2008年4月2日星期三

导出为Excel 文件

[php]
// define database parameter
$db_server = "localhost";
$db_username = "root";
$db_password = "****";
$db_dbname = "db";
$db_tblname = "table";

// connect database
$connect = @mysql_connect($db_server, $db_username, $db_password) or die("couldn't connect.");
$db = @mysql_select_db($db_dbname, $connect) or die("couldn't select database.");

// set header infomation
$file_type = "vnd.ms-excel";
$file_ending = "xls";
header("content-type: application/$file_type");
header("content-disposition: attachment; filename=$db_tblname . $file_ending");
header("pragma: no-cache");
header("expires: 0");

//export data to excel
$now_date = date('y-m-d h:i');
$title = "数据库名 : $db_dbname, 数据表:$db_tblname, 备份日期: $now_date";
echo("$title\n");

$sql = "SELECT * FROM $db_tblname";
$alt_db = @mysql_select_db($db_dbname, $connect) or die("couldn't select database");
$result = @mysql_query($sql,$connect) or die(mysql_error());

$sep = "\t";
for ($i = 0; $i < mysql_num_fields($result); $i++) {
echo mysql_field_name($result,$i) . "\t";
}
print("\n");
$i = 0;
while($row = mysql_fetch_row($result)) {
$schema_insert = "";
for($j = 0; $j < mysql_num_fields($result); $j++) {
if(!isset($row[$j]))
$schema_insert .= "null".$sep;
elseif ($row[$j] != "")
$schema_insert .= "$row[$j]" . $sep;
else
$schema_insert .= "" .$sep;
}
$schema_insert = str_replace($sep . "$", "", $schema_insert);
$schema_insert .= "\t";
print(trim($schema_insert));
print "\n";
$i++;
}
return (true);
[/php]

2008年2月27日星期三

Prototype and jQuery are used in same time

[js]
<script language="javascript" type="text/javascript">var jQuery=$;</script>
<script language="javascript" type="text/javascript">jQuery.noConflict();</script>
[/js]

2008年2月11日星期一

魔术引号

FROM:

魔术引号(Magic Quote)是一个自动将进入 PHP 脚本的数据进行转义的过程。最好在编码时不要转义而在运行时根据需要而转义。

什么是魔术引号?
当打开时,所有的 ' (单引号), " (双引号), \ (反斜线)和 NULL 字符都会被自动加上一个反斜线进行转义。这和 addslashes() 作用完全相同。

一共有三个魔术引号指令:

  • magic_quotes_gpc 影响到 HTTP 请求数据(GET,POST 和 COOKIE)。不能在运行时改变。在 PHP 中默认值为 on 。参见 get_magic_quotes_gpc()

  • magic_quotes_runtimeoff 。参见 set_magic_quotes_runtime()get_magic_quotes_runtime()

  • magic_quotes_sybase 如果打开的话,将会使用单引号对单引号进行转义而非反斜线。此选项会完全覆盖 magic_quotes_gpc。如果同时打开两个选项的话,单引号将会被转义成 '' 。而双引号、反斜线 和 NULL 字符将不会进行转义。如何取得其值参见ini_get()



为什么要用魔术引号

  • 对初学者很有用
    魔术引号在 PHP 中用来实现避免初学者的代码更危险。尽管 SQL 注入 在魔术引号打开的情况下仍然有可能实现,但起码系统的风险减少很多了。

  • 方便使用
    当向数据库中插入数据时,魔术引号所做的就是自动对所有的 GET、POST、COOKIE 数据运用 addslashes() 函数。



为什么不用魔术引号

  • 可移植性
    编程时认为其打开或并闭都会影响到移植性。可以用 get_magic_quotes_gpc() 来检查是否打开,并据此编程。

  • 性能
    由于并不是每一段被转义的数据都要插入数据库的,如果所有进入 PHP 的数据都被转义的话,那么会对程序的执行效率产生一定的影响。在运行时调用转义函数(如 addslashes())更有效率。
    尽管 php.ini-dist 默认打开了这个选项,但是 php.ini-recommended 默认却关闭了它,主要是出于性能的考虑。

  • 不便
    由于不是所有数据都需要转义,在不需要转义的地方看到转义的数据就很烦。比如说通过表单发送邮件,结果看到一大堆的 \'。针对这个问题,可以使用 stripslashes()函数处理。



关闭魔术引号
magic_quotes_gpc 指令只能在系统级关闭,不能在运行时。也就是说不能用 ini_set()
[bash title="下面是一个通过 php.ini 文件把这些选项设为 Off 的范例"]
; Magic quotes
;

; Magic quotes for incoming GET/POST/Cookie data.
magic_quotes_gpc = Off

; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.
magic_quotes_runtime = Off

; Use Sybase-style magic quotes (escape ' with '' instead of \').
magic_quotes_sybase = Off
[/bash]

如果不能修改服务器端的配置文件,使用 .htaccess 也可以。范例如下:
[bash]
php_flag magic_quotes_gpc Off
[/bash]

为了能写出移植性较强的代码(可以运行于任何环境),例如不能修改服务器配置的情况,下面的例子可以在运行时关闭 magic_quotes_gpc 。但是这样做比较低效,适当的修改配置才是更好的办法。

[php title="在运行时关闭魔术引号"]
if ( get_magic_quotes_gpc()) {
function stripslashes_deep ($value) {
$value = is_array($value) ?
array_map('stripslashes_deep', $value) :
stripslashes($value);
return $value ;
}

$_POST = array_map ('stripslashes_deep', $_POST);
$_GET = array_map ('stripslashes_deep', $_GET);
$_COOKIE = array_map ('stripslashes_deep', $_COOKIE);
}

function addslashes_deep($var) {
if(is_array($var)) {
return array_map('addslashes_deep',$var);
} else {
if(get_magic_quotes_gpc()) {
// 如果 magic_quotes_sybase=On,我们先把 " 替换成 ',然后再addslashes
if(ini_get('magic_quotes_sybase')) {
$var = str_replace("\"", "'", $var);
$var = addslashes($var);
}
} else {
$var = addslashes($var);
}
return trim($var);
}
}
[/php]

PHP程序员的十个建议性技巧


  • 使用 ip2long()long2ip() 函数来把 IP 地址转化成整型存储到数据库里。这种方法把存储空间降到了接近四分之一(char(15) 的 15 个字节对整形的 4 个字节),计算一个特定的地址是不是在一个区段内页更简单了,而且加快了搜索和排序的速度(虽然有时仅仅是快了一点)。

  • 在验证 email 地址的时候使用 checkdnsrr() 函数验证域名是否存在。这个内置函数能够确认指定的域名能够解析成 IP 地址。该函数的PHP 文档的用户评论部分有一个简单的用户自定义函数,这个函数基于 checkdnsrr(),用来验证 email 地址的合法性。对于那些认为自己的 email 地址是 "joeuser@wwwphp.net" 而不是 "joeuser@php.net" 的家伙们,这个方法可以很方便的抓住他们。

  • 如果你使用的是 PHP 5 和 MySQL 4.1 或者更高的版本,考虑抛弃 mysql_* 系列函数, 改用改进版的 mysqli_* 系列函数。一个很好的功能就是你可以使用预处理语句,如果你在维护一个数据库密集型站点,这个功能能够加快查询速度。

  • 学会爱上三元运算符。

  • 如果你在项目中感觉到有可复用的部分,在你写下一行代码前先看看 PEAR 中是否已经有了。很多 PHP 程序员都知道 PEAR 是一个很好的资源库,虽然还有很多程序员不知道。这个在线资源库包含了超过 400 个可以复用的程序片段,这些程序片段你可以立即用在你的程序里。除非说你的项目真的是非常特别的,你总能找到帮你节省时间的 PEAR 包. (参见 PECL)

  • highlight_string(), highlight_file() 来自动的打印出格式化的很漂亮的源代码。如果你在留言板、IRC 这些地方寻求一个脚本的帮助的话,这个函数用起来非常的顺手。当然了,要小心不要意外的泄露出你的数据库连接信息和密码等。

  • 使用 error_reporting(0) 函数来防止用户看到潜在的敏感错误信息。在理想情况下,发布服务器应该在 php.ini 里完全禁止。但是如果你用的是一个共享的 web 服务器的话,没有自己的 php.ini 文件,那么这种情况下最好的选择就是在所有脚本的第一行前加上 error_reporting(0);(或者使用 require_once()方法)。这就能够在出错的时候完全屏蔽敏感的 SQL 查询语句和路径名。

  • 在网数据库中存储很大的字符串之前使用 gzcompress()gzuncompress() 来显式的压缩/解压字符串。这个 PHP 内置函数使用 gzip 算法,可以压缩普通文本达 90%。在我每次要读写 BLOB 类型的字段的时候都使用这些函数。唯一额例外就是当我需要全文检索的时候。

  • 通过引用 传递参数的方法从一个函数中得到多个返回值。就像三元运算符一样,大部分受过正式编程训练的程序员都知道这个技巧。但是那些 HTML 背景大于 Pascal 背景的程序员都或多或少的有过这样的疑问 "在仅能使用一次 return 的情况下,从一个函数里返回多个值?" 答案就是在变量前加上一个 & 符号,通过引用传递而非"值"传递。

  • 完全理解魔术引号 SQL 注入的危险性。

PHP 注意事项


  • 页面之间无法传递变量 get,post,session
    php5后自动全局变量是关闭的,所以要从上一页面取得提交过来得变量要使用$_GET['test'], $_POST['test'], $_SESSION['test'] 来得到
    当然也可以修改自动全局变量,将register_globals = On 考虑到安全性和兼容性,最好不要这样操作。


  • Win32下apache2 用get方法传递中文参数会出错
    test.php?a=你好&b=你也好 传递参数是会导致一个内部错误
    解决办法: "test.php?a=" . urlencode('你好') . "&b=" . urlencode('你也好');

  • win32下的session不能正常工作
    php.ini 默认的 session.save_path = /tmp, 这是*nix下的配置,win32下php无法读写session文件导致session无法使用

  • 显示错误信息
    当php.ini的display_errors = On并且error_reporting = E_ALL 时,将显示所有的错误和提示

  • Win32下 mail()不能发送电子邮件
    在*nix下配置好的 sendmail 可以发送,在win32下需要有smtp服务器才可以发送电子邮件
    修改php.ini的
    [bash]
    SMTP = ip //ip是不带验证功能的smtp服务器
    [/bash]
    php发送邮件的最好解决方法是用socket直接发送到对方email服务器而不用转发服务器


  • 初装的mysql如果没有设置密码, 应该使用
    [sql]
    UPDATE mysql.user SET PASSWORD ="yourpassword" WHERE user="root";
    [/sql]

  • header already sent
    这个错误通常会在使用header()的时候出现,可能是几种原因:
    A. 在使用header()前有print 或者echo
    B. 当前文件前面有空行
    C. 可能include了一个文件,该文件尾部有空行或者有输出


  • 更改php.ini后没有变化
    重新启动web server,比如IIS,Apache等等,然后才会应用最新的设置


  • php在2003上面安装
    PHP4的php4isapi.dll好像和2003有些冲突,只能用CGI模式安装

  • isset()和empty()的区别
    两者都是测试变量,但是isset()是测试变量是否被赋值,而empty()是测试一个已经被赋值的变量是否为空
    如果一个变量没被赋值就引用在php里是被允许的,但会有notice提示
    如果一个变量被赋空值,$foo=""或者$foo=0或者 $foo=false,那么empty($foo)返回真,isset($foo)也返回真,就是说赋空值不会注销一个变量。
    要注销一个变量,可以用 unset($foo)或者$foo=NULL

  • mysql查询语句包含有关键字
    php查询mysql的时候,有时候mysql表名或者列名会有关键字
    这时候查询会有错误。例如表名是order,查询时候会出错
    简单的办法是sql语句里表名或者列名加上`[tab键上面]来加以区别, 例如 SELECT * FROM `order`

  • 通过HTTP协议一次上传文件
    form 需要 enctype="multipart/form-data" 这个属性



include,require,include_once,require_once的区别
A. include()函数会将指定的档案读入并且执行里面的程序。
被导入的档案中的程序代码都会被执行,而且这些程序在执行的时候会拥有和源文件中呼叫到include()函数的位置相同的变量范围 (variable scope) 。你可以导入同一个服务器中的静态档案,甚至可以通过合并使用include()与fopen()函数来导入其它服务器上面的档案。

B. include_once()函数的作用和include()是几乎相同的
唯一的差别在于include_once()函数会先检查要导入的档案是不是已经在该程序中的其它地方被导入过了,如果有的话就不会再次重复导入该档案 (这项功能有时候是很重要的,比方说要导入的档案里面宣告了一些你自行定义好的函数,那么如果在同一个程序重复导入这个档案,在第二次导入的时候便会发生错误讯息,因为PHP不允许相同名称的函数被重复定义) 。

C. require()函数会将目标档案的内容读入,并且把自己本身代换成这些读入的内容。
这个读入并且代换的动作是在PHP引擎编译你的程序代码的时候发生的,而不是发生在PHP引擎开始执行编译好的程序代码的时候 (PHP 3.0引擎的工作方式是编译一行执行一行,但是到了PHP 4.0就有所改变了,PHP 4.0是先把整个程序代码全部编译完成后,再将这些编译好的程序代码一次执行完毕,在编译的过程中不会执行任何程序代码) 。require()通常来导入静态的内容,而include()则适合用来导入动态的程序代码。

D. 如同include_once()函数,require_once()函数会先检查目标档案的内容是不是在之前就已经导入过了,如果是的话,便不会再次重复导入同样的内容。
如果要包含的文件不存在,include提示notice,然后继续执行下面的语句,require提示致命错误并且退出

E. 对include()来说,在include()执行时文件每次都要进行读取和评估;而对于require()来说,文件只处理一次 (实际上,文件内容替换了require()语句) 。

F. include(), The include() 语句包括并运行指定文件。
以下文档也适用于 require()。这两种结构除了在如何处理失败之外完全一样。include() 产生一个警告而 require() 则导致一个致命错误。换句话说,如果你想在遇到丢失文件时停止处理页面就用 require()。include() 就不是这样,脚本会继续运行。同时也要确认设置了合适的 include_path。

当一个文件被包括时,其中所包含的代码继承了 include 所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。
[php title="基本的 include() 例子 vars.php"]

$color = 'green';
$fruit = 'apple';

[/php]

[php title="test.php"]
echo "A $color $fruit"; // A
include 'vars.php';
echo "A $color $fruit"; // A green apple
[/php]

如果 include 出现于调用文件中的一个函数里,则被调用的文件中所包含的所有代码将表现得如同它们是在该函数内部定义的一样。所以它将遵循该函数的变量范围。
[php title="函数中的包括"]
function foo() {
global $color;
include 'vars.php';
echo "A $color $fruit";
}

/* vars.php 是在foo()函数中被include, 所以$fruit 在foo()函数外它是不可用的,
* 而$color已被定义为全局变量,所以它是可用的
*/

foo(); // A green apple
echo "A $color $fruit"; // A green
[/php]
当一个文件被包括时,语法解析器在目标文件的开头脱离 PHP 模式并进入 HTML 模式,到文件结尾处恢复。由于此原因,目标文件中应被当作 PHP 代码执行的任何代码都必须被包括在有效的 PHP 起始和结束标记之中。

如果 "URL fopen wrappers" 在 PHP 中被激活 (默认配置) ,可以用 URL (通过 HTTP) 而不是本地文件来指定要被包括的文件。如果目标服务器将目标文件作为 PHP 代码解释,则可以用适用于 HTTP GET 的 URL 请求字符串来向被包括的文件传递变量。严格的说这和包括一个文件并继承父文件的变量空间并不是一回事;该脚本文件实际上已经在远程服务器上运行了,而本地脚本则包括了其结果。

Notice:Windows 版本的 PHP 目前还不支持该函数的远程文件访问,即使 allow_url_fopen 选项已被激活。
[php title="通过 HTTP 进行的 include()"]
/* This example assumes that www.example.com is configured to parse .php *
* files and not .txt files. Also, 'Works' here means that the variables *
* $foo and $bar are available within the included file. */

/*Won't work; file.txt wasn't handled by www.example.com as PHP include
'http://www.example.com/file.txt?foo=1&bar=2';
*/

// Won't work; looks for a file named 'file.php?foo=1&bar=2' on the
// local filesystem.
include 'file.php?foo=1&bar=2';

// Works.
include 'http://www.example.com/file.php?foo=1&bar=2';

$foo = 1;
$bar = 2;
include 'file.txt'; // Works.
include 'file.php'; // Works.
[/php]

相关信息参见使用远程文件,fopen() 和 file()。
因为 include() 和 require() 是特殊的语言结构,在条件语句中使用必须将其放在语句组中 (花括号中) 。
[php language="title="与条件语句组"]
// This is WRONG and will not work as desired.
if ($condition)
include $file;
else
include $other;


// This is CORRECT.
if ($condition) {
include $file;
} else {
include $other;
}
[/php]

处理返回值:可以在被包括的文件中使用 return() 语句来终止该文件中程序的执行并返回调用它的脚本。同样也可以从被包括的文件中返回值。可以像普通函数一样获得 include 呼叫的返回值。

注: 在 PHP 3 中,除非是在函数中调用否则被包括的文件中不能出现 return。在此情况下 return() 作用于该函数而不是整个文件。
[php title="include() 和 return() 语句 return.php"]
$var = 'PHP';
return $var;
[/php]
[php title="noreturn.php"]
$var = 'PHP';
[/php]
[php title="testreturns.php"]
$foo = include 'return.php';
echo $foo; // prints 'PHP'
$bar = include 'noreturn.php';
echo $bar; // prints 1
[/php]

$bar 的值为 1 是因为 include 成功运行了。注意以上例子中的区别。第一个在被包括的文件中用了 return() 而另一个没有。其它几种把文件 包括 到变量的方法是用 fopen(),file() 或者 include() 连同输出控制函数一起使用。

如果一个文件不想被包含多次可以使用include_once或require_once读取,写入文档数据
[php]
function r($file_name) {
$filenum = @fopen($file_name, "r");
@flock($filenum, LOCK_SH);
$file_data = @fread($filenum, filesize($file_name));
@fclose($filenum);
return $file_data;
}
function w($file_name, $data, $method = "w"){
$filenum = @fopen($file_name, $method);
flock($filenum, LOCK_EX);
$file_data = fwrite($filenum, $data);
fclose($filenum);
return $file_data;
[/php]

2008年1月27日星期日

PHP get client IP and ip2long function

[php title="得到客户端IP地址"]
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$realip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
$realip = $_SERVER['HTTP_CLIENT_IP'];
} else {
$realip = $_SERVER['REMOTE_ADDR'];
}

$realip = ip2long($realip);
[/php]

ip2long 两个算法:

[php]
function ip2int($ip){
//我们先把ip分为四段,$ip1,$ip2,$ip3,$ip4
list($ip1,$ip2,$ip3,$ip4) = explode('.', $ip);
//然后第一段乘以256的三次方,第二段乘以256的平方,第三段乘以256
return $ip1*pow(256,3)+$ip2*pow(256,2)+$ip3*256+$ip4;
}
[/php]

[php title="用位运算"]
function ip2int($ip){
list($ip1,$ip2,$ip3,$ip4)=explode('.', $ip);
return($ip1>>24)|($ip2>>16)|($ip3>>8)|($ip4);
}
[/php]

有些ip转化成整数后,是负数,这是因为得到的结果是有符号整型,最大值是2147483647.要把它转化为无符号的,可以用sprintf("%u",ip2long($ip); 就能转换为正整数。而且得到的结果用long2ip可以正常转换回原来的ip地址。

ip2long也可以用于检测一个IP地址的有效性
int ip2long (string ip_address )

The function ip2long() generates an IPv4 Internet network address from its Internet standard format (dotted string) representation. If ip_address is invalid then -1 is returned. Note that -1 does not evaluate as FALSE in PHP.

注: As of PHP 5.0.0 ip2long() returns FALSE when ip_address is invalid

T-SQL

FROM: http://www.winmag.com.cn/forum/itemdisplay.asp?boardid=11&id=503269
T-SQL允许你使用不同的方法解决一个问题.有的时候,尽管选择不是那么明显,但是却可以让你得到令人满意的和快乐的惊奇.下边让我们解读Dr. Tom Moreau对同一问题不同的可能性的探索.可能我们可以在那些不同的方法之中发现一些珍贵的东西.

让我们以我们的老朋友Northwind数据库为例,这里我们用到的是[order details]表,这个表是一个定单的明细表,和order表是多对一的关系.也就是一个定单对应多个订购的产品.假设你想得到每个定单订购的总价值, 但是不包括59号产品.Listing 1给了我们第一种解法:
[sql title="Listing 1"]
select
OrderID,sum (Quantity * UnitPrice) value
from
[Order Details] o1
where
ProductID <> 59
group by
OrderID
[/sql]
上边的语句很简单,它排除掉了59号产品的定单明细条目,然后进行分组统计.但是如果我们需要忽略掉订购59号产品的定单呢?也就是说我们要统计没 有包含 59号产品的定单的价值.你想到了WHERE, NOT EXIST(S)关键词了吗?Listing 2给了我们第二种方法:
[sql title="Listing 2"]
select
o1.OrderID,sum (o1.Quantity * o1.UnitPrice) value
from
[Order Details] o1
where not exists
(
select
*
from
[Order Details] o2
where
o2.OrderID = o1.OrderID
and o2.ProductID = 59
)
group by
o1.OrderID
[/sql]
如果你不喜欢用exist的话,你可以转化成使用not in:
[sql title="Listing 3"]
select
o1.OrderID,sum (o1.Quantity * o1.UnitPrice) value
from
[Order Details] o1
where 59 not in
(
select
ProductID
from
[Order Details] o2
where
o2.OrderID = o1.OrderID
)
group by
o1.OrderID
[/sql]
尽管Listing 1不满足我们现在的查询条件.但是从性能发面考虑,Listing 1还是最好的,因为它只用到了一次表的扫描.而后边的两个查询都是用到了相关子查询,如果你查看查询计划就回看到,他们都涉及到了两次表的扫描.如果你曾经在 T-SQL用过交叉表查询的话,你就不会对聚集函数里边的case结构陌生.现在我们就把这个非常有趣的方法应用到我们的问题中来:
[sql title="Listing 4"]
select
OrderID,sum (Quantity * UnitPrice) value
from
[Order Details] o1
group by
OrderID
having
sum (case when ProductID = 59 then 1 else 0 end) = 0
[/sql]

HAVING子句起到了对分组的结果进行过滤的作用.如果没有包含59号产品,就会出现0=0,显然这是满足条件的.如果包含了59号产品的订购,就会出现n=0(n<>0),这样的定单就回被过滤掉.查看执行计划你就回发现是一次表的扫描,非常棒!
再来举一个例子:我们这回用到的表是order表,假设我们要统计只通过一个雇员雇员下定单的顾客.你可以想到用子查询not exist来实现:
[sql title="Listing 5"]
select distinct
o1.CustomerID
from
Orders o1
where not exists
(
select
*
from
Orders o2
where
o2.CustomerID = o1.CustomerID
and o2.EmployeeID <> o1.EmployeeID
)
[/sql]
同样的,这个语句可以通过带有HAVING子句的分组来实现.
[sql title="Listing 6"]
select
CustomerID
from
Orders
group by
CustomerID
having
min (EmployeeID) = max (EmployeeID)
[/sql]
另一种方法:
[sql title="Listing 7"]
select
CustomerID
from
Orders
group by
CustomerID
having
count (distinct EmployeeID) = 1
[/sql]

Listing 6和Listing 7查询消耗都要小于Listing 5.相比Listing 5的两次表扫描,他们只进行一次表的扫描.而Listing 6的损耗还要稍微小于Listing 7.但是,Listing 7的一个显著的特点就是它可以适应到一个顾客对应两个雇员,三个雇员......

SQL高手篇:精妙SQL语句介绍

说明:复制表(只复制结构,源表名:a 新表名:b)
SQL: select * into b from a where 1<>1
  说明:拷贝表(拷贝数据,源表名:a 目标表名:b)
SQL: insert into b(a, b, c) select d,e,f from b;
  说明:显示文章、提交人和最后回复时间
SQL: select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b
  说明:外连接查询(表名1:a 表名2:b)
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
  说明:日程安排提前五分钟提醒

  SQL: select * from 日程安排 where datediff('minute',f开始时间,getdate())>5

  说明:两张关联表,删除主表中已经在副表中没有的信息
SQL:

delete from info where not exists ( select * from infobz where info.infid=infobz.infid )
  说明:--
SQL:

SELECT A.NUM, A.NAME, B.UPD_DATE, B.PREV_UPD_DATE FROM TABLE1,(SELECT X.NUM, X.UPD_DATE, Y.UPD_DATE PREV_UPD_DATE FROM (SELECT NUM, UPD_DATE, INBOUND_QTY, STOCK_ONHAND FROM TABLE2 WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = TO_CHAR(SYSDATE, 'YYYY/MM')) X, (SELECT NUM, UPD_DATE, STOCK_ONHAND FROM TABLE2 WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = TO_CHAR(TO_DATE(TO_CHAR(SYSDATE, 'YYYY/MM') ¦¦ '/01','YYYY/MM/DD') - 1, 'YYYY/MM') ) Y, WHERE X.NUM = Y.NUM (+)AND X.INBOUND_QTY + NVL(Y.STOCK_ONHAND,0) <> X.STOCK_ONHAND ) B WHERE A.NUM = B.NUM
  说明:--
SQL:

select * from studentinfo where not exists(select * from student where studentinfo.id=student.id) and 系名称='"&strdepartmentname&"' and 专业名称='"&strprofessionname&"' order by 性别,生源地,高考总成绩
  说明: 从数据库中去一年的各单位电话费统计(电话费定额贺电化肥清单两个表来源)
SQL:

SELECT a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy') AS telyear, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '01', a.factration)) AS JAN, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '02', a.factration)) AS FRI, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '03', a.factration)) AS MAR, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '04', a.factration)) AS APR, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '05', a.factration)) AS MAY, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '06', a.factration)) AS JUE,SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '07', a.factration)) AS JUL, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '08', a.factration)) AS AGU, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '09', a.factration)) AS SEP, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '10', a.factration)) AS OCT, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '11', a.factration)) AS NOV,SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '12', a.factration)) AS DEC FROM (SELECT a.userper, a.tel, a.standfee, b.telfeedate, b.factration FROM TELFEESTAND a, TELFEE b WHERE a.tel = b.telfax) a GROUP BY a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy')
  说明:四表联查问题:
SQL: select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....
  说明:得到表中最小的未使用的ID号
SQL:

SELECT (CASE WHEN EXISTS(SELECT * FROM Handle b WHERE b.HandleID = 1) THEN MIN(HandleID) + 1 ELSE 1 END) as HandleID FROM Handle WHERE NOT HandleID IN (SELECT a.HandleID - 1 FROM Handle a)

2008年1月18日星期五

FireFox 插件

就开发上而言,目前还没发现一款可以和FF比拟的浏览器,只是有时它占CPU太多,让人不得不在喜欢的同时不免轻叹一声~ “任何东西都是无法十全十美的吧~”。

FireFox的强大,终归于还是它的插件的强大~


FireBug
这是开发时怎样我也不愿意缺少的插件,调样式,调布局,调JS,调AJXA....总之,它的作用太多..

WebDeveloper
这款插件,也可以看样式,另外,它还可以看提交的表单情况,还有一点,可以根据需要清 Cookie


All-in-one Gesture
鼠标手势~用过遨游的人就知道,按住鼠标右键,画来画去,是有惊喜出现的~

ColorZilla
这款在用于取得某个布局的颜色,十六进制的,RBG 值的都有

GoogleToolbar
Google 出的,肯定不会逊色,只是有点太庞大(也许是我心理作用,总感觉装了这个后,FF占CPU就更恐怖了)~

Easy Drugtogo
与 All-in-one Gesture 搭配使用~

Screenrab
截图~