chenery's profile小陈空间PhotosBlogListsMore Tools Help

chenery

Occupation
Location

Windows Media Player

小陈空间

态度决定一切!只要努力,就必定能成功!我相信我自己能行!
August 29

MySQL优化实例【一】

MySQL优化实例

在Apache, PHP, MySQL的体系架构中,MySQL对于性能的影响最大,也是关键的核心部分。对于Discuz!论坛程序也是如此,MySQL的设置是否合理优化,直接影响到论坛的速度和承载量!同时,MySQL也是优化难度最大的一个部分,不但需要理解一些MySQL专业知识,同时还需要长时间的观察统计并且根据经验进行判断,然后设置合理的参数。

下面我们了解一下MySQL优化的一些基础,MySQL的优化我分为两个部分,一是服务器物理硬件的优化;二是MySQL自身(my.cnf)的优化。

(1) 服务器硬件对MySQL性能的影响

a) 磁盘寻道能力(磁盘I/O),以目前高转速SCSI硬盘(7200转/秒)为例,这种硬盘理论上每秒寻道7200次,这是物理特性决定的,没有办法改变。MySQL每秒钟都在进行大量、复杂的查询操作,对磁盘的读写量可想而知。所以,通常认为磁盘I/O是制约MySQL性能的最大因素之一,对于日均访问量在100万PV以上的Discuz!论坛,由于磁盘I/O的制约,MySQL的性能会非常低下!解决这一制约因素可以考虑以下几种解决方案:

使用RAID-0+1磁盘阵列,注意不要尝试使用RAID-5,MySQL在RAID-5磁盘阵列上的效率不会像你期待的那样快; 抛弃传统的硬盘,使用速度更快的闪存式存储设备。经过Discuz!公司技术工程的测试,使用闪存式存储设备可比传统硬盘速度高出6-10倍左右。

b) CPU 对于MySQL应用,推荐使用S.M.P.架构的多路对称CPU,例如:可以使用两颗Intel Xeon 3.6GHz的CPU。

c) 物理内存对于一台使用MySQL的Database Server来说,服务器内存建议不要小于2GB,推荐使用4GB以上的物理内存。

(2) MySQL自身因素当解决了上述服务器硬件制约因素后,让我们看看MySQL自身的优化是如何操作的。对MySQL自身的优化主要是对其配置文件my.cnf中的各项参数进行优化调整。下面我们介绍一些对性能影响较大的参数。

由于my.cnf文件的优化设置是与服务器硬件配置息息相关的,因而我们指定一个假想的服务器硬件环境:

CPU: 2颗Intel Xeon 2.4GHz

内存: 4GB DDR

硬盘: SCSI 73GB

下面,我们根据以上硬件配置结合一份已经优化好的my.cnf进行说明:

# vi /etc/my.cnf

以下只列出my.cnf文件中[mysqld]段落中的内容,其他段落内容对MySQL运行性能影响甚微,因而姑且忽略。

  [mysqld]
  port = 3306
  serverid = 1 
  socket = /tmp/mysql.sock
  skip-locking
  # 避免MySQL的外部锁定,减少出错几率增强稳定性。
  skip-name-resolve

禁止MySQL对外部连接进行DNS解析,使用这一选项可以消除MySQL进行DNS解析的时间。但需要注意,如果开启该选项,则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求!

back_log = 384

指定MySQL可能的连接数量。当MySQL主线程在很短的时间内接收到非常多的连接请求,该参数生效,主线程花费很短的时间检查连接并且启动一个新线程。

back_log参数的值指出在MySQL暂时停止响应新请求之前的短时间内多少个请求可以被存在堆栈中。 如果系统在一个短时间内有很多连接,则需要增大该参数的值,该参数值指定到来的TCP/IP连接的侦听队列的大小。不同的操作系统在这个队列大小上有它自己的限制。

试图设定back_log高于你的操作系统的限制将是无效的。默认值为50。对于Linux系统推荐设置为小于512的整数。

     key_buffer_size = 256M
  # key_buffer_size指定用于索引的缓冲区大小,增加它可得到更好的索引处理性能。
对于内存在4GB左右的服务器该参数可设置为256M或384M。
注意:该参数值设置的过大反而会是服务器整体效率降低! max_allowed_packet = 4M thread_stack = 256K table_cache = 128K sort_buffer_size = 6M

查询排序时所能使用的缓冲区大小。注意:该参数对应的分配内存是每连接独占!如果有100个连接,那么实际分配的总共排序缓冲区大小为100 × 6 = 600MB。所以,对于内存在4GB左右的服务器推荐设置为6-8M。

 read_buffer_size = 4M

读查询操作所能使用的缓冲区大小。和sort_buffer_size一样,该参数对应的分配内存也是每连接独享!

join_buffer_size = 8M

联合查询操作所能使用的缓冲区大小,和sort_buffer_size一样,该参数对应的分配内存也是每连接独享!

     myisam_sort_buffer_size = 64M
    table_cache = 512
    thread_cache_size = 64
    query_cache_size = 64M

指定MySQL查询缓冲区的大小。可以通过在MySQL控制台执行以下命令观察:

 # > SHOW VARIABLES LIKE '%query_cache%';
 # > SHOW STATUS LIKE 'Qcache%';
 # 如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲不够的情况;

如果Qcache_hits的值非常大,则表明查询缓冲使用非常频繁,如果该值较小反而会影响效率,那么可以考虑不用查询缓冲;Qcache_free_blocks,如果该值非常大,则表明缓冲区中碎片很多。

     tmp_table_size = 256M
    max_connections = 768

指定MySQL允许的最大连接进程数。如果在访问论坛时经常出现Too Many Connections的错误提 示,则需要增大该参数值。

     max_connect_errors = 10000000
    wait_timeout = 10

指定一个请求的最大连接时间,对于4GB左右内存的服务器可以设置为5-10。

     thread_concurrency = 8

该参数取值为服务器逻辑CPU数量×2,在本例中,服务器有2颗物理CPU,而每颗物理CPU又支持H.T超线程,所以实际取值为4 × 2 = 8

    skip-networking

开启该选项可以彻底关闭MySQL的TCP/IP连接方式,如果WEB服务器是以远程连接的方式访问MySQL数据库服务器则不要开启该选项!否则将无法正常连接!  

July 11

提高HTML代码的效率

许多网站设计者最常犯的错误便是当其网页能够在IE下正常显示便认为其代码正确无误,甚至常看到有人在抱怨其网站排名不理想,到其网站简单看一下便可发现 HTML代码中充斥各种各样的错误,在那样的代码基础上无论付出多少努力去优化网站结果都可能是付诸流水的啊!事实上,IE是一款对HTML代码容错能力甚高的的浏览器,——说句题外话,尽管我们可以有各式各样的理由可以攻击微软,但微软对其产品操作的易手性及可用性方面所做的努力是不容抹杀的。——Web页面能够在IE下正常显示绝不意味着页面的HTML代码没有问题,甚至可以推而广之,Web页面在多种浏览器下均可正常显示也不意味着HTML代码完全合法有效,毕竟哪个浏览器都要保证基本的容错的功能,不然,就会发生即使仅仅因为网络传输中的一点导致导致 HTML页面显示不正常了,而这在网络带宽仍然紧张的今天仍是频繁发生的。

什么是合法有效的HTML代码

同其他语言一样,HTML也有自己的语法规则,无论是浏览器还是搜索引擎的Spider都在根据这些规则来分析网页代码中的内容。但很多时候,即使对熟练人员来说,在HTML页面构建时仍然难免出些HTML代码上的错误,更别提大部分所见即所得编辑器造成的HTML冗余臃肿问题了。
   
如果页面中不存在违背HTML标准语法规范的成分,即可被称为合法有效的HTML代码


合法有效的HTML代码对SEO的重要性

    要使搜索引擎收录我们的网页,——在此基础上才能谈网站优化网站推广——其前提是要让搜索引擎的Spider能读懂我们的Web文件。搜索引擎 Spider阅读网页的根据便是HTML规范,通过对HTML代码的分析,Spider才能判断网页内容,在此基础上才能判断针对相应关键词的相关性。
    需要明确的是,搜索引擎Spider不同于浏览器的一点便是其容错能力相对于浏览器要差不少,如果页面代码中存在其无法解释的HTML代码时,其便可能停止阅读该页面甚至可能停止在我们的网站内爬行,更严重的错误甚至会导致其同时也丢弃已经收集到的网站内其他页面的内容信息。
    尽管如今如大主要搜索引擎也都在尽力提高Spider的容错能力,让其可以在HTML代码出现一般性错误时不至影响对内容的收集。但很多时候,仍然会发生如漏了一个关闭标签导致整个页面的内容被忽略的情况。
    另一方面,合法有效的HTML也可以保证Web页面可以在多种浏览器下被正确解释,避免同一个页面在IE下显示正常在Mozilla下却严重变形的情况(当然,不能完全避免),这对于提高网站的可用性方面也是有着极大
好处的。

如何验证HTML代码的合法有效?

    Internet有很多类似的免费服务可以帮我们验证网页代码是否合法有效,其中最著名的即是 W3C HTMLValidator,这是由W3C( World Wide WebConsortium:万维网联盟)官方推出的免费服务项目,在其页面上只需输入待验证的HTML地址或者上传一个在本地机上的HTML文件即可,其会很快返回校验结果,是否无误,如有错误分别为哪些及如何改进等。
同时,W3C HTML Validator也提供对CSS文件的验证服务。

提高HTML代码的效率

    前文我们提说过很多所见即所得编辑器造成的HTML冗余臃肿问题,这种情况在很多中文网站相当普遍。所见即所得编辑器如FrontPage、 Dreamweaver,尤其在其对一个网页进行修改的时候,往往会产生很多不必要的冗余代码。当页面的HTML文件在存在大量的冗余代码时,文件便会变得臃肿,这不但会降低网页的打开速度,损害到网页的效率,同时也会严重影响到相当网页的搜索引擎排名。
    与其把精力投入到一定通过W3C认证上,个人认为,倒不如把更多的精力放到精减代码上,如引入CSS等,以实现代码的干净简洁。这样的优化效果会更明显。

榨干php 提高效率

这篇杂文翻译整理自网络各路文档资料(见最末的参考资料),尤其是 Ilia Alshanetsky (佩服之至) 在多个 PHP 会议上的演讲,主要是各类提高 PHP 性能的技巧。为求精准,很多部分都有详细的效率数据,以及对应的版本等等。偷懒,数据就不一一给出了,直接给结论,如果需要看原文档,请到文末「参考资料」部分。橙色标题为推荐部分。

========================================================

静态调用的成员一定要定义成 static  (PHP5 ONLY)

贴士:PHP 5 引入了静态成员的概念,作用和 PHP 4 的函数内部静态变量一致,但前者是作为类的成员来使用。静态变量和 Ruby 的类变量(class variable)差不多,所有类的实例共享同一个静态变量。

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
class foo {
    function 
bar() {
        echo 
'foobar';
    }
}

$foo = new foo;

// instance way

$foo->bar();

// static way

foo::bar();
?>

静态地调用非 static 成员,效率会比静态地调用 static 成员慢 50-60%。主要是因为前者会产生 E_STRICT 警告,内部也需要做转换。

使用类常量 (PHP5 ONLY)

贴士:PHP 5 新功能,类似于 C++ 的 const。

使用类常量的好处是:

- 编译时解析,没有额外开销
- 杂凑表更小,所以内部查找更快
- 类常量仅存在于特定「命名空间」,所以杂凑名更短
- 代码更干净,使除错更方便

(暂时)不要使用 require/include_once 

require/include_once 每次被调用的时候都会打开目标文件!

- 如果用绝对路径的话,PHP 5.2/6.0 不存在这个问题
- 新版的 APC 缓存系统已经解决这个问题

文件 I/O 增加 => 效率降低

如果需要,可以自行检查文件是否已被 require/include。

不要调用毫无意义的函数

有对应的常量的时候,不要使用函数。

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
php_uname
('s') == PHP_OS;
php_version() == PHP_VERSION;
php_sapi_name() == PHP_SAPI;
?>

虽然使用不多,但是效率提升大概在 3500% 左右。

最快的 Win32 检查

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
$is_win 
DIRECTORY_SEPARATOR == '\\';
?>


- 不用函数
- Win98/NT/2000/XP/Vista/Longhorn/Shorthorn/Whistler...通用
- 一直可用

时间问题 (PHP>5.1.0 ONLY)

你如何在你的软件中得知现在的时间?简单,「time() time() again, you ask me...」。

不过总归会调用函数,慢。

现在好了,用 $_SERVER['REQUEST_TIME'],不用调用函数,又省了。

加速 PCRE

- 对于不用保存的结果,不用 (),一律用 (?

这样 PHP 不用为符合的内容分配内存,省。效率提升 15% 左右。

- 能不用正则,就不用正则,在分析的时候仔细阅读手册「字符串函数」部分。有没有你漏掉的好用的函数?

例如:

strpbrk()
strncasecmp()
strpos()/strrpos()/stripos()/strripos()

加速 strtr

如果需要转换的全是单个字符的时候,用字符串而不是数组来做 strtr:

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
$addr 
strtr($addr"abcd""efgh"); // good
$addr strtr($addr, array('a' => 'e',
                           
// ...
                           
)); // bad
?>

效率提升:10 倍。

不要做无谓的替换

即使没有替换,str_replace 也会为其参数分配内存。很慢!解决办法:

- 用 strpos 先查找(非常快),看是否需要替换,如果需要,再替换

效率:

- 如果需要替换:效率几乎相等,差别在 0.1% 左右。
- 如果不需要替换:用 strpos 快 200%。

邪恶的 @ 操作符

不要滥用 @ 操作符。虽然 @ 看上去很简单,但是实际上后台有很多操作。用 @ 比起不用 @,效率差距:3 倍。

特别不要在循环中使用 @,在 5 次循环的测试中,即使是先用 error_reporting(0) 关掉错误,在循环完成后再打开,都比用 @ 快。

善用 strncmp

当需要对比「前 n 个字符」是否一样的时候,用 strncmp/strncasecmp,而不是 substr/strtolower,更不是 PCRE,更千万别提 ereg。strncmp/strncasecmp 效率最高(虽然高得不多)。

慎用 substr_compare (PHP5 ONLY)

按照上面的道理,substr_compare 应该比先 substr 再比较快咯。答案是否定的,除非:

- 无视大小写的比较
- 比较较大的字符串

不要用常量代替字符串

为什么:

- 需要查询杂凑表两次
- 需要把常量名转换为小写(进行第二次查询的时候)
- 生成 E_NOTICE 警告
- 会建立临时字符串

效率差别:700%。

不要把 count/strlen/sizeof 放到 for 循环的条件语句中

贴士:我的个人做法

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
for ($i 0$max count($array);$i $max; ++$i);
?>

效率提升相对于:

- count 50%
- strlen 75%

短的代码不一定快

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
// longest
if ($a == $b) {
    
$str .= $a;
} else {
    
$str .= $b;
}

// longer
if ($a == $b) {
    
$str .= $a;
}
$str .= $b;

// short
$str .= ($a == $b $a $b);
?>

你觉得哪个快?

效率比较:

- longest: 4.27
- longer: 4.43
- short: 4.76

不可思议?再来一个:

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
// original
$d dir('.');
while ((
$entry $d->read()) !== false) {
    if (
$entry == '.' || $entry == '..') {
        continue;
    }
}

// versus
glob('./*');

// versus (include . and ..)
scandir('.');
?>

哪个快?

效率比较:

- original: 3.37
- glob: 6.28
- scandir: 3.42
- original without OO: 3.14
- SPL (PHP5): 3.95

画外音:从此也可以看出来 PHP5 的面向对象效率提高了很多,效率已经和纯函数差得不太多了。

提高 PHP 文件访问效率

需要包含其他 PHP 文件的时候,使用完整路径,或者容易转换的相对路径。

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php

include 'file.php'// bad approach

incldue './file.php'// good

include '/path/to/file.php'// ideal

?>

物尽其用

PHP 有很多扩展和函数可用,在实现一个功能的之前,应该看看 PHP 是否有了这个功能?是否有更简单的实现?

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
$filename 
"./somepic.gif";
$handle fopen($filename"rb");
$contents fread($handlefilesize($filename));
fclose($handle);

// vs. much simpler

file_get_contents('./somepic.gif');
?>

关于引用的技巧

引用可以:

- 简化对复杂结构数据的访问
- 优化内存使用

QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
$a
['b']['c'] = array();

// slow 2 extra hash lookups per access
for ($i 0$i 5; ++$i)
    
$a['b']['c'][$i] = $i;

// much faster reference based approach
$ref =& $a['b']['c'];
for (
$i 0$i 5; ++$i)
    
$ref[$i] = $i;
?>



QUOTE:
// PHP CODE Highliting for CU by dZ902

<?php
$a 
'large string';

// memory intensive approach
function a($str)
{
    return 
$str.'something';
}

// more efficient solution
function a(&$str)
{
    
$str .= 'something';
}
?>

==============================================
参考资料

http://ilia.ws

Ilia 的个人网站,Blog,他参与的开发以及出版的一些稿物链接等等。

http://ez.no

eZ components 官方网站,eZ comp 是针对 PHP5 的开源通用库,以效率为己任,Ilia 也参与了开发。

http://phparch.com

php|architect,不错的 php 出版商/培训组织。买不起或者买不到的话,网上可以下到很多经典的盗版。

http://talks.php.net

PHP 会议上的演讲合集,现在还不是很丰富,不过内容都是让人一看就容易废寝忘食的好东东,推荐早上睡眼朦胧的时候或者吃完午饭仔细研究,否则你会忘记吃饭和睡觉的!

============================================================================

在进行大型系统的开发的时候,我总是困饶,是否应该包含每一个可能用到的类库文件。
        如果只是在使用中才包含,会给开发带来很大的麻烦。因为我不可能预先知道在哪个地方会使用到哪个类。而且,如果在每个页面中,根据需要进行require或include,这是令人很头疼的,我们往往会因为忘记include而导致一个warning或fatal。
        如果在一个全局文件中包含所有的类库,然后所有的页面都包含这个全局文件。这样,虽然简化了include的工作,但是却带来了效率的下降。因为php会对每一个包含在内的文件进行检测。虽然PHP的效率很高,但是检测一大堆的类,还是会带来一些性能的下降的,特别是在一个大型系统中。
        是不是有方法可以两全其美呢?肯定有了,不然我就不打这么多字了。
方法就是工厂模式。具体工厂模式是什么,我就不说了,这个已经被程序员们说到烂了。
        我们建立以下四个文件
index.php
[复制PHP代码]PHP代码如下
php
include_once(f.inc.php);
$f=new factory;
$t1=&$f-create('T1');
echo $t1-getName();
echo $config;


f.inc.php
[复制PHP代码]PHP代码如下
php
class factory
{
    function factory()
    {
        $this-mClasses=array('T1'='t1.inc.php','T2'='t2.inc.php');
    }
    function &create($class)
    {
        if (!class_exists($class))
        {
            require_once($this-mClasses[$class]);
        }
        return new $class;
    }
}


t1.inc.php
[复制PHP代码]PHP代码如下
php
global $config;
$config='surfchen';
class T1
{
    var $mName='nameT1';
    function getName()
    {
        return $this-mName;
    }
}


t2.inc.php
[复制PHP代码]PHP代码如下
php
class T2
{
    function T2()
    {
        echo 't2 is ok';
    }
}


在index.php里,我们通过一个factory类来创建其他的类实例。
在factory里,保存有一个数组$this-mClasses,格式为array(”类名”=”类文件路径”).
我们通过factorycreate()来创建一个类实例的时候,在create()里,会首先检测类是否存在,如果不存在,就根据$this-mClasses把类对应的类文件包含进来。然后创建并返回一个该类的实例。
        这样,我们只需要把factory类文件包含进执行的脚本(如index.php)中就可以了。
        大家可能还注意到了在t1.inc.php中的这两行代码。
global $config;
$config=’surfchen’;
        为什么需要global呢?因为t1.inc.php是在factorycreate中被包含的,t1文件中的变量将会默认为create的函数级变量。所以我们需要对其中的变量(如$config)进行global以便index.php能访问到。
        运行index.php,将会输出
nameT1surfchen

========================================================================
(继续添加中...)

June 12

图片处理类

/**
 *名称:Image.class.php
 *作用:公共处理类
 *说明:
 功  能:利用PHP的GD库生成高质量的缩略图
 运行环境:PHP5.01/GD2
 类说明:可以选择是/否裁图。
 如果裁图则生成的图的尺寸与您输入的一样。
 原则:尽可能多保持原图完整
 如果不裁图,则按照原图比例生成新图
 原则:根据比例以输入的长或者宽为基准
 参 数:$img:源图片地址
 $wid:新图的宽度
 $hei:新图的高度
 $c:是否裁图,1为是,0为否
 *版权:
 *作者:
 *时间:2005-4-23
 **/
class Image
{
    //图片类型
    var $type;
    //实际宽度
    var $width;
    //实际高度
    var $height;
    //改变后的宽度
    var $resize_width;
    //改变后的高度
    var $resize_height;
    //是否裁图
    var $cut;
    //源图象
    var $srcimg;
    //目标图象地址
    var $dstimg;
    //临时创建的图象
    var $im;
    function Resize($img, $wid, $hei,$c, $dimg='')
    {
        $this->srcimg = $img;
        $this->resize_width = $wid;
        $this->resize_height = $hei;
        $this->cut = $c;
        //图片的类型
        $this->type = strtolower(substr(strrchr($this->srcimg,"."),1));
  //目标图象地址
  $this->dstimg = ($dimg) ? $dimg.".".$this->type : $this->srcimg;
        //初始化图象
        $this->initi_img();
  $pic = getimagesize($this->srcimg);
        $this->width = $pic[0];
        $this->height = $pic[1];
        //生成图象
        $this->newimg();
        ImageDestroy ($this->im);
    }
    function newimg()
    {
        //改变后的图象的比例
        $resize_ratio = ($this->resize_width)/($this->resize_height);
        //实际图象的比例
        $ratio = ($this->width)/($this->height);
        if(($this->cut)=="1")
        //裁图
        {
            if($ratio>=$resize_ratio)
            //高度优先
            {
                $newimg = imagecreatetruecolor($this->resize_width,$this->resize_height);
                imagecopyresampled($newimg, $this->im, 0, 0, 0, 0, $this->resize_width,$this->resize_height, (($this->height)*$resize_ratio), $this->height);
                ImageJpeg ($newimg,$this->dstimg);
            }
            if($ratio<$resize_ratio)
            //宽度优先
            {
                $newimg = imagecreatetruecolor($this->resize_width,$this->resize_height);
                imagecopyresampled($newimg, $this->im, 0, 0, 0, 0, $this->resize_width, $this->resize_height, $this->width, (($this->width)/$resize_ratio));
                ImageJpeg ($newimg,$this->dstimg);
            }
        }
        else
        //不裁图
        {
            if($ratio>=$resize_ratio)
            {
                $newimg = imagecreatetruecolor($this->resize_width,($this->resize_width)/$ratio);
                imagecopyresampled($newimg, $this->im, 0, 0, 0, 0, $this->resize_width, ($this->resize_width)/$ratio, $this->width, $this->height);
                ImageJpeg ($newimg,$this->dstimg);
            }
            if($ratio<$resize_ratio)
            {
                $newimg = imagecreatetruecolor(($this->resize_height)*$ratio,$this->resize_height);
                imagecopyresampled($newimg, $this->im, 0, 0, 0, 0, ($this->resize_height)*$ratio, $this->resize_height, $this->width, $this->height);
                ImageJpeg ($newimg,$this->dstimg);
            }
        }
    }
    //初始化图象
    function initi_img()
    {
        if($this->type=="jpg")
        {
            $this->im = imagecreatefromjpeg($this->srcimg);
        }
        if($this->type=="gif")
        {
            $this->im = imagecreatefromgif($this->srcimg);
        }
        if($this->type=="png")
        {
            $this->im = imagecreatefrompng($this->srcimg);
        }
    }
 //返回:width="",height=""
 function DisplaySize($file,$w_size,$h_size)
    {
  if(file_exists($file))
  {
   $image_size = getimagesize($file);
   if($w_size > $h_size) {  //设定图像宽大于高
    if($image_size[0] >= $image_size[1] && $image_size[0] >= $w_size)
    {
     if(($image_size[0]/$image_size[1])<=($w_size/$h_size))
     {
      return("height=\"".$h_size."\"");
     } else {
      return("width=\"".$w_size."\"");
     }
    }
    if($image_size[0] < $image_size[1] && $image_size[1] >= $h_size)
    {
     return("height=\"".$h_size."\"");
    }
    if($image_size[0] <= $w_size && $image_size[1] <= $h_size)
    {
     return ("");
    }
   } elseif($w_size == $h_size) { //设定图像宽等于高
    if($image_size[0] >= $image_size[1] && $image_size[0] >= $w_size)
    {
     return ("width=\"".$w_size."\"");
    }
    if($image_size[0] < $image_size[1] && $image_size[1] > $h_size)
    {
     return ("height=\"".$h_size."\"");
    }
    if($image_size[0] <= $w_size && $image_size[1] <= $h_size)
    {
     return ("");
    }
   } else { //设定图像宽小于高
    if($image_size[1] >= $image_size[0] && $image_size[1] >= $h_size)
    {
     if(($image_size[0]/$image_size[1])<=($w_size/$h_size))
     {
      return("height=\"".$h_size."\"");
     } else {
      return("width=\"".$w_size."\"");
     }
    }
    if($image_size[1] < $image_size[0] && $image_size[0] >= $w_size)
    {
     return("width=\"".$w_size."\"");
    }
    if($image_size[0] <= $w_size && $image_size[1] <= $h_size)
    {
     return ("");
    }
   }
  }
 }
 
/**
 *  图片水印方法
 *  运行环境:PHP5.01/GD2 
 *  功能:把上传图片加上水印 
 *
 * 
 */
    var $groundImage;    //上传的图片
    var $groundImageWidth;   //上传图片的宽
    var $groundImageHeight;  //上传图片的高
    var $groundImageHandle;  //上传图片的标识
    var $waterType;    //水印类型,0是文字,1是图片
    var $waterPosType;    //水印在图片的位置
    var $waterPosX;    //水印在图片中的X位置
    var $waterPosY;    //水印在图片中的Y位置
    var $waterWidth;    //水印图片的宽
    var $waterHeight;    //水印图片的高
    var $waterImage;    //水印图片
    var $waterImageType;   //水印图片的类型标记( = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM)
    var $waterImageHandle;   //水印图片的类型标记
 // var $waterImageAlpha;
    var $waterText;    //水印文本
    var $waterTextColor;   //文本颜色
    var $waterTextSize;   //文本大小
    var $waterTextFont;   //文本字体
    var $errorMsg;     //错误信息
    //设置图片水印,$groundImage 上传图片名;$waterPosType 在图片中的位置
    function PhpUpImageWater($groundImage = "demo.jpg", $waterPosType = 0)
    {
        if(false == file_exists($groundImage))
        {
            $this->throwError("groundImage404");
        }
        $this->checkGD();
        $this->groundImage   =  &$groundImage;
        $this->waterType     =  &$waterType;
        $this->waterPosType  =  &$waterPosType;
        $this->setGroundImageInfo();
    }
 //检查GD库
    function checkGD()
    {
        if(false == function_exists("gd_info"))
        {
            $this->throwError("NonGD");
        }
    }
 //获得上传图片信息
    function setGroundImageInfo()
    {
        $groundImageType   =  getimagesize($this->groundImage);
        $this->groundImageWidth  =  $groundImageType[0];
        $this->groundImageHeight =  $groundImageType[1];
        $this->groundImageType   =  $groundImageType[2];
        if($this->groundImageWidth < 150 or $this->groundImageHeight < 150)
        {
            $this->throwError("TooSmall");
        }
    }
 //设置文字水印
    function setWaterTextInfo($waterText = "phpup.com",$waterTextColor = "#000000", $waterTextSize = "5", $waterTextFont = "./couri.ttf")
    {
        $this->waterType   =  0;
        if(strlen($waterTextColor) == 7)
        {
            $this->waterTextColor = &$waterTextColor;
        }
        else
        {
            $this->throwError("WrongColor");
        }
        $this->waterText       =   &$waterText;
        $this->waterTextSize   =   &$waterTextSize;
        $this->waterTextFont   =   &$waterTextFont;
        $waterTextInfo = imagettfbbox(ceil($this->waterTextSize*1.2), 0, $this->waterTextFont, $this->waterText); 
        $this->waterWidth    =  $waterTextInfo[4] - $waterTextInfo[6]; 
        $this->waterHeight   =  $waterTextInfo[1] - $waterTextInfo[7]; 
        unset($waterTextInfo);
    }
 
 //设置图片水印
    function setWaterImageInfo($waterImage = "/server/www/tel168/tpl/images/shuiyin.png")
    {
        if(file_exists($waterImage))
        {
            $this->waterType       =   1;
            $this->waterImage      =   &$waterImage;
            $waterImageInfo        =   getimagesize($this->waterImage);
            $this->waterWidth      =   $waterImageInfo[0];
            $this->waterHeight     =   $waterImageInfo[1];
            $this->waterImageType  =   $waterImageInfo[2];
            unset($waterImageInfo);
        }
        else
        {
            $this->throwError("waterImage404");
        }
    }
 //设置水印在上传图片中的位置
    function setWaterPos()
    {
        switch($this->waterPosType) 
        { 
            case 0://随机 
                $this->waterPosX = rand(0,($this->groundImageWidth - $this->waterWidth)); 
                $this->waterPosY = rand(0,($this->groundImageHeight - $this->waterHeight)); 
                break; 
            case 1://1为顶端居左 
                $this->waterPosX = 0; 
                $this->waterPosY = 0; 
                break; 
            case 2://2为顶端居中 
                $this->waterPosX = ($this->groundImageWidth - $this->waterWidth) / 2; 
                $this->waterPosY = 0; 
                break; 
            case 3://3为顶端居右 
                $this->waterPosX = $this->groundImageWidth - $this->waterWidth; 
                $this->waterPosY = 0; 
                break; 
            case 4://4为中部居左 
                $this->waterPosX = 0; 
                $this->waterPosY = ($this->groundImageHeight - $this->waterHeight) / 2; 
                break; 
            case 5://5为中部居中 
                $this->waterPosX = ($this->groundImageWidth - $this->waterWidth) / 2; 
                $this->waterPosY = ($this->groundImageHeight - $this->waterHeight) / 2; 
                break; 
            case 6://6为中部居右 
                $this->waterPosX = $this->groundImageWidth - $this->waterWidth; 
                $this->waterPosY = ($this->groundImageHeight - $this->waterHeight) / 2; 
                break; 
            case 7://7为底端居左 
                $this->waterPosX = 0; 
                $this->waterPosY = $this->groundImageHeight - $this->waterHeight * rand(115,125) / 100; 
                break; 
            case 8://8为底端居中 
                $this->waterPosX = ($this->groundImageWidth - $this->waterWidth) / 2; 
                $this->waterPosY = $this->groundImageHeight - $this->waterHeight * rand(115,125) / 100; 
                break; 
            case 9://9为底端居右 
                $this->waterPosX = $this->groundImageWidth - $this->waterWidth; 
                $this->waterPosY = $this->groundImageHeight - $this->waterHeight * rand(115,120) / 100; 
                break; 
            default://随机 
                $this->waterPosX = rand(0,($this->groundImageWidth - $this->waterWidth)); 
                $this->waterPosY = rand(0,($this->groundImageHeight - $this->waterHeight));     
        }
    }

    function setGroundImageHandle()
    {
        switch($this->groundImageType) 
        {
            case 1:
                $this->groundImageHandle = imagecreatefromgif($this->groundImage);
                break; 
            case 2:
                $this->groundImageHandle = imagecreatefromjpeg($this->groundImage);
                break; 
            case 3:
                $this->groundImageHandle = imagecreatefrompng($this->groundImage);
                break; 
            default:
                $this->throwError("NonType"); 
        }
    }
    function setWaterImageHandle()
    {
        switch($this->waterImageType) 
        {
            case 1:
                $this->waterImageHandle = imagecreatefromgif($this->waterImage);
                break; 
            case 2:
                $this->waterImageHandle = imagecreatefromjpeg($this->waterImage);
                break; 
            case 3:
                $this->waterImageHandle = imagecreatefrompng($this->waterImage);
                break; 
            default:
                $this->throwError("NonType"); 
        }
    }
 //创建新图片
    function putWateredImage($extFileName)
    {
        switch($this->groundImageType) 
        {
            case 1:
                imagegif($this->groundImageHandle, $extFileName.$this->groundImage);
                break; 
            case 2:
                imagejpeg($this->groundImageHandle, $extFileName.$this->groundImage);
                break; 
            case 3:
                imagepng($this->groundImageHandle, $extFileName.$this->groundImage);
                break; 
            default:
                $this->throwError("NonType"); 
        }        
    }
 //销毁图像
    function destroyHandle()
    {
        imagedestroy($this->groundImageHandle);
        if(isset($this->waterImageHandle))
        {
            imagedestroy($this->waterImageHandle);
        }
    }
 //生成水印图片
    function makeWater($extFileName = "")
    {
        $this->setGroundImageHandle();
        $this->setWaterPos();
        imagealphablending($this->groundImageHandle, true); 
        if($this->waterType == 0)
        {
            imagettftext($this->groundImageHandle, $this->waterTextSize, 0, $this->waterPosX, $this->waterHeight + $this->waterPosY, imagecolorallocate($this->groundImageHandle, hexdec(substr($this->waterTextColor,1,2)), hexdec(substr($this->waterTextColor,3,2)), hexdec(substr($this->waterTextColor,5,2))), $this->waterTextFont, $this->waterText);
        }
        else
        {
            $this->setWaterImageHandle();
            imagecopy($this->groundImageHandle,$this->waterImageHandle , $this->waterPosX, $this->waterPosY, 0, 0, $this->waterWidth,$this->waterHeight);
        }
        @unlink($this->groundImage);
        $this->putWateredImage($extFileName);
        $this->destroyHandle();
    }
//异常模块
    function throwError($errType)
    {
        switch($errType)
        {
            case "TooSmall":
                $this->errorMsg = "要打水印图片太小";
                break;
            case "groundImage404":
                $this->errorMsg = "要打水印图片不存在";
                break;
            case "waterImage404":
                $this->errorMsg = "水印图片不存在";
                break;
            case "NonGD":
                $this->errorMsg = "没有安装GD库";
                break;
            case "NonType":
                $this->errorMsg = "不支持的文件格式";
                break;
            case "WrongColor":
                $this->errorMsg = "错误的颜色格式";
                break;
            default:
                $this->errorMsg = "未知错误";
        }
            
        die($this->errorMsg);
        exit();
    }
}

SHELL自动备份脚本

#!/bin/bash
#
#Role : Backup procedures
#Note : Monday complete backup ,Tuesday to Sunday Incremental Backup
#Parameter Description
# Parameter 1:Backup directory name [Directory document addresses or Directory name]
# Parameter 2:Backup level [0:Backup database and Web 1:Backup Web 2:Backup database]
#Original Author: Hongbin.Chen <chenunix@gmail.com>
backup_run ()
{
 [ -d "$1" ] || return 0
 file_dir="$1"
 backup_dir="$2/`date +%G%m`/"
 [ -d "$backup_dir" ]|| mkdir -p "$backup_dir"
 DAT=`date | awk '{print $1}'`
 if [ $DAT = 'Mon' ]
 then
         filename="`date +%d`.tar.gz"
         [ -f $backup_dir$filename ] || tar cvfz $backup_dir$filename $file_dir
 else
         filename="`date +%d`.tar.gz"
         t1=`date +%d`
         t2=`expr $t1 - 1 `
         yesterday=`date +%Y\/%m\/`$t2
         tar -cvz -N "$yesterday" -f $backup_dir$filename $file_dir
 fi
}
backupDir="/server/backup"
webDir="/server/www"
dataDir="/server/soft/mysql/data"
if [ -f "$1" ]
then
 while read line;
 do
  if [ ! -n "$2" ] || [ "$2" = "0" ]
                then
                        [ -d "$webDir/$line" ] && backup_run "$webDir/$line" "$backupDir/web/$line"
              [ -d "$dataDir/$line" ] && backup_run "$dataDir/$line" "$backupDir/data/$line"
  elif [ "$2" = "1" ]
  then
          [ -d "$webDir/$line" ] && backup_run "$webDir/$line" "$backupDir/web/$line"
  elif [ "$2" = "2" ]
  then
   [ -d "$dataDir/$line" ] && backup_run "$dataDir/$line" "$backupDir/data/$line"
  fi
 done < $1
elif [  -n "$1" ]
then
         if [ ! -n "$2" ] || [ "$2" = "0" ]
                then
                        [ -d "$webDir/$1" ] && backup_run "$webDir/$1" "$backupDir/web/$1"
                        [ -d "$dataDir/$1" ] && backup_run "$dataDir/$1" "$backupDir/data/$1"
                elif [ "$2" = "1" ]
                then
                        [ -d "$webDir/$line" ] && backup_run "$webDir/$1" "$backupDir/web/$1"
                elif [ "$2" = "2" ]
                then
                        [ -d "$dataDir/$line" ] && backup_run "$dataDir/$1" "$backupDir/data/$1"
                fi
else
  backup_run "$webDir" "$backupDir/web"
  backup_run "$dataDir" "$backupDir/data"
fi
 
Photo 1 of 40
No list items have been added yet.