经典,完美抓取页面程序原理

<?php
/*
描述:从0a上抓取站点信息
作者:xuduowei
日期:2011.02.12
*/
class getInfoController extends tcoaBaseController{

protected $getInfoModel;
public function set_getInfoModel($getInfoModel){
$this->getInfoModel=$getInfoModel;
}
//载入checkSessionModel模型,方便后面调用里面的方法,如:域名列表显示
protected $checkSessionModel;
public function set_checkSessionModel($checkSessionModel){
$this->checkSessionModel=$checkSessionModel;
}

//jquery调用方法
public function getInfo(){
$domain=trim($_POST[‘domain’]);
$domainarr=$this->getInfoModel->listsite($domain);
$old_timeout=ini_get(‘default_socket_timeout’);
ini_set(‘default_socket_timeout’,15); //设置file_get_contents 取值超时,当前是15秒

foreach($domainarr as $domainname){
$ftpdomain=$domainname[‘ftp_domain’];
$siteipold=$domainname[‘siteip’];
$ftp_userold=$domainname[‘ftp_user’];
$ftp_passold=$domainname[‘ftp_pass’];
$db_hostold=$domainname[‘db_host’];
$db_userold=$domainname[‘db_user’];
$db_passold=$domainname[‘db_pass’];
$serveripold=$domainname[‘serverip’];

$domainarr=explode(“www.”,$ftpdomain);
$begainurl=Project::singleton()->getConfig(‘customConfig.getInterfaceURL’);//其中getInterfaceURL为tcoaBaseController中的一个自定义变量(接口路径)。
$url=$begainurl.$domainarr[1];

$jsoncon=””;
$i=0;
if(function_exists(“file_get_contents”)){
while($i<3&&empty($jsoncon)){
$i++;
$jsoncon=file_get_contents($url);
}
}elseif(function_exists(‘curl_init’)){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$jsoncon = curl_exec ($ch);
curl_close ($ch);
}
if(!empty($jsoncon)){
// $jsoncon=file_get_contents($url);//若直接这样写的话,不是很完美。参看行28-39
$ans = json_decode($jsoncon,true);
$siteip=$ans[“ip”];
$ftpuser=$ans[“ftpuser”];
$ftppwd=$ans[“ftppwd”];

$dbuser=$ans[“dbuser”];
$dbpwd=$ans[“dbpwd”];
$db=$ans[“db”];
$siteip2=$siteip;
$serverip=$ans[“server”];
//从oa上获得信息后,按域名更新相应的信息。
$this->getInfoModel->updateinfo($siteip2,$ftpuser,$ftppwd,$siteip2,$dbuser,$dbpwd,$db,$serverip,$ftpdomain);
if(!empty($ftpdomain)){
if($siteipold==$siteip){
$str.=”成功更改:”.$ftpdomain.”–原子站ip:”.$siteipold.”–<font color=red>更改后:”.$siteip.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原ftp用户名:”.$ftp_userold.”–<font color=red>更改后:”.$ftpuser.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原ftp密码:”.$ftp_passold.”–<font color=red>更改后:”.$ftppwd.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原数据库用户名:”.$db_userold.”–<font color=red>更改后:”.$dbuser.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原数据库密码:”.$db_passold.”–<font color=red>更改后:”.$dbpwd.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原服务器ip:”.$serveripold.”–<font color=red>更改后:”.$serverip.”</font><br/>”;
echo $str;
}else{
$str.=”成功更改:”.$ftpdomain.”–原子站ip:<font color=blue>”.$siteipold.”</font>–<font color=red>更改后:”.$siteip.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原ftp用户名:<font color=blue>”.$ftp_userold.”</font>–<font color=red>更改后:”.$ftpuser.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原ftp密码:<font color=blue>”.$ftp_passold.”</font>–<font color=red>更改后:”.$ftppwd.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原数据库用户名:<font color=blue>”.$db_userold.”</font>–<font color=red>更改后:”.$dbuser.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原数据库密码:<font color=blue>”.$db_passold.”</font>–<font color=red>更改后:”.$dbpwd.”</font><br/>”;
$str.=”成功更改:”.$ftpdomain.”–原服务器ip:<font color=blue>”.$serveripold.”</font>–<font color=red>更改后:”.$serverip.”</font><br/>”;
echo $str;
}
}
}else{
$str=”<font color=red>更改失败!!!!!!!</font>”.$ftpdomain.”–原ip:”.$siteipold.”<br/>”;
echo $str;
}
if(!empty($ftpdomain)){
$this->insertLog($ftpdomain,$str);
}
}//结束foreach
ini_set(‘default_socket_timeout’,$old_timeout);
}//结束function

//视图方法
public function showGetInfo(){
$this->getInfo();
$View=ViewDepository::singleton()->imLoad(‘./tcoaView/getInfoView.php’);
$View->showtypename=$this->checkSessionModel->listtypename();
echo $View->render();
}

//写日志方法
public function insertLog($domain,$str){
$time=time();
$group_id= $this->userName.”_”.date(“YnjHis”);
//$tj=” group_id=’$group_id’,domain=’$domain’,description=’$str’,checktime=’$time'”;
$arrdomain=$this->getInfoModel->insertlog($group_id,$domain,$str,$time);
}
}
?>

MySQL查询及删除重复记录的方法

查询及删除重复记录的方法
(一)
1、查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断

select * from people where peopleId in (select peopleId from people group by peopleId having count(peopleId) > 1)

2、删除表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断,只留有rowid最小的记录

delete from people where peopleId in (select peopleId from people group by peopleId having count(peopleId) > 1) and rowid not in (select min(rowid) from people group by peopleId having count(peopleId )>1)

3、查找表中多余的重复记录(多个字段)

select * from vitae a where (a.peopleId,a.seq) in (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1)

4、删除表中多余的重复记录(多个字段),只留有rowid最小的记录

delete from vitae a where (a.peopleId,a.seq) in (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1) and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)

5、查找表中多余的重复记录(多个字段),不包含rowid最小的记录

select * from vitae a where (a.peopleId,a.seq) in (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1) and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)

(二)
比方说
在A表中存在一个字段“name”,
而且不同记录之间的“name”值有可能会相同,
现在就是需要查询出在该表中的各记录之间,“name”值存在重复的项;

Select Name,Count(*) From A Group By Name Having Count(*) > 1

如果还查性别也相同大则如下:

Select Name,sex,Count(*) From A Group By Name,sex Having Count(*) > 1

(三)
方法一

declare @max integer,@id integer

declare cur_rows cursor local for select 主字段,count(*) from 表名 group by 主字段 having count(*) >; 1

open cur_rows

fetch cur_rows into @id,@max

while @@fetch_status=0

begin

select @max = @max -1

set rowcount @max

delete from 表名 where 主字段 = @id

fetch cur_rows into @id,@max

end

close cur_rows

set rowcount 0

方法二

有两个意义上的重复记录,一是完全重复的记录,也即所有字段均重复的记录,二是部分关键字段重复的记录,比如Name字段重复,而其他字段不一定重复或都重复可以忽略。

1、对于第一种重复,比较容易解决,使用

select distinct * from tableName

就可以得到无重复记录的结果集。

如果该表需要删除重复的记录(重复记录保留1条),可以按以下方法删除

select distinct * into #Tmp from tableName

drop table tableName

select * into tableName from #Tmp

drop table #Tmp

发生这种重复的原因是表设计不周产生的,增加唯一索引列即可解决。

2、这类重复问题通常要求保留重复记录中的第一条记录,操作方法如下

假设有重复的字段为Name,Address,要求得到这两个字段唯一的结果集

select identity(int,1,1) as autoID, * into #Tmp from tableName

select min(autoID) as autoID into #Tmp2 from #Tmp group by Name,autoID

select * from #Tmp where autoID in(select autoID from #tmp2)

最后一个select即得到了Name,Address不重复的结果集(但多了一个autoID字段,实际写时可以写在select子句中省去此列)

(四)
查询重复

select * from tablename where id in (select id from tablename group by idhaving count(id) > 1);

ecshop页面纯静态生成方法

ECSHOP是一套非常不错的开源网站程序,本身的优化也做得不错,不过很多东西都是动态的,如果简单的生成伪静态,很有可能会造成多种URL同时存在,LEO从网上找了下ECSHOP生成纯静态(HTML)的方法,先给大家贴出来,抽时间试验下!

1.复制首页index.php为index_html.php,因为ECSHOP是使用SMARTY模板引擎的,所以我们可以使用SMARTY生成文件函数,把模板的静态网页输出。

在首页中,$smarty->display(‘index.dwt’, $cache_id);有这一句,说明是把网页显示出来,现在我们把它改成如下代码(参看注释)
$file = ‘index.html’;//静态网页文件名
$content = $GLOBALS[‘smarty’]->make_html(‘index.dwt’);//根据index.dwt模板生成网页内容
$filename = ROOT_PATH . $file;//静态网页路径
file_put_contents($filename, $content);//生成文件

以上几条简单的语句,我们就可以生成首页的静态网页。同理,我们可以生成产品类别和产品的静态网页,整个系统的静态化就完成了。

桌面上的快速启动没有了

如果快速启动栏里面的“显示桌面”被误删或消失了!只要新建个文本文档输入一下内容

[Shell]

Command=2

IconFile=explorer.exe,3

[Taskbar]

Command=ToggleDesktop

 

在新建文档中选择“文件”菜单—“另存为……”—文件类型选择为“所有文件”—文件名为“显示桌面.SCF”—成功啦!

小技巧:在“IconFile=explorer.exe,3”里面的“3”改为“4”就变成打印机的图表,因此只要把“3”这个位置的数字替换为相应的数字便可达到更换图表的效果!

谈一下怎样判断网页是静态的还是伪静态的?

怎样判断网页是静态还是伪静态呢?

SEO文章看多了,经常能听到静态、伪静态这类的词语,那什么样的网页是静态的,什么样的网页是伪静态的呢?

IE5浏览器以上:
打开你想判断的网站后,再在网址框中输入javascript:alert(document.lastModified)
IE5以上… ,此方法可以判断一个网页的最后更新时间,如果这个时间与现在的时间相同,说明是伪静态的,反之为静态的。

火狐浏览器下:

先用火狐打开一个网页如:http://bbs.ittang.com/forum-13-1.html 等网页完全打开后进入FireFox的控制台。”工具”-“错误控制台”快捷键:shift+ctrl+J 然后在控制台里面输入:alert(document.lastModified); 查看最后修改时间并记录。

接下来关闭控制台,重新刷新网页,再用相同的方法在控制台里输入查询代码,再查看文件的最后修改时间,连续几次如果发现时间不同则可以判断它是伪静态的了

相关知识:关于伪静态和真静态网页用处和利弊对比

1.关于伪静态的用处
有些用户觉得,伪静态和真静态实际被收录量会相差很大,其实不然,从你个人角度,你去判断一下一个帖子到底是真静态还是伪静态?
估计很难看得出,因为所谓静态的意思,就是地址中不带问号,不带问号的就是静态,管他是真的还是伪的?搜索引擎看得出吗?
所以说,其实不论是真的还是伪的,其实对于搜索引擎来说都是一样的,搜索引擎没有说,你这个是伪的,我不收录你.
揪根掘底的来说,为什么搜索引擎会不收录带问号的网址?因为搜索引擎怕由于问号而进入死循环(以前动网就有这样一个漏洞,蜘蛛进去出不来了),所以很多时候带问号的地址是不会进去的,伪静态对于搜索引擎来说,其实就是静态,因为地址中没有带问号,所以没有真静态比伪静态收录得多的说法.

2.为什么选择伪静态
有很多用户说:
真静态不好吗?
为什么不用真静态?
访问起来不是更快吗?
负载不是更好吗?
等等等等…
在这里,其实只用一个问题来回答:为什么选择MYSQL.
很多用户大概不明白为什么那么多大型论坛都选择了MYSQL数据库作为储存机制,大概大部分都是想:”因为DZ用了MYSQL,所以就是MYSQL”.
其实不然,试想DZ为什么会在那么多论坛程序并存的日子生存下来并笑傲江湖,很大原因是因为DZ用了MYSQL.试想如果大C当年改的程序是一个文本论坛,那还会有DZ的今天吗?
或者从另一个角度问,为什么那么多大型网站都选择了MYSQL而不是文本作为储存机制?
所谓文本论坛,实际就跟真静态的说法差不多了,将数据储存在空间上面,大量读写硬盘,等等…
为什么这种写法会被淘汰呢?
我相信答案不会是老师所说的:

“discuz.net 目前有 2129867 篇帖子,存储成html的话大约是 20799 M,也就是 20G左右。这当中还不计算由于磁盘存储机制造成的空间浪费(100个1k 的文件占用的空间可能会是200K)。”

这种说法从我个人观点来看,这个理由不能给予用户不使用真静态充分的理由.
然而,另一个理由却是值得我们注意思考的,也是为什么绝大多数站都不选择生成静态:

“删除、更新这些html内容会导致大量的磁盘io操作以及大量的磁盘碎片.”

正如上面这个说法,在实际当中确实会导致大量的磁盘I/O操作(input,output),大量进行I/O操作带来的后果可想而知,会产生大量的磁盘碎片甚至会导致硬盘出现坏道.

所以对于生成静态而言,还不如去用文本论坛,可以更好的解决你们的需求.
(副W就是做文本论坛出生的,当时的名字为ofstar http://www.ofstar.net ,后因发展困难转为MYSQL,而PW生成静态页面也就是PW以前文本方式稍加改进用于吸引用户眼球的噘头)
当然,如果大家记忆力好的话,应该可以记得PW4的时候PW论坛不能访问很长一段时间,后来恢复到一段时间前的数据,官方的说法是被人攻击而导致硬盘损坏,其实这种说法是比较不可信的,相对于是被攻击导致硬盘损坏还是大量I/O操作而产生的后果,我个人更倾向于后者.

当然,如果大家比较关注5d6d的话,应该知道前几天有一天时间5d6d无法访问,根据非官方消息是因为硬盘坏了,而损坏的原因我想当然是因为大量用户大量进行I/O操作了,试想,我们一个论坛,进行磁盘I/O操作的仅为管理员进行更新缓存时进行的,而5d6d每一个会员就是一个管理员,试想下对磁盘是多大的考验?所以我并不奇怪5d6d的硬盘坏了.

当然,也许在读这篇文章的很多朋友都有使用过BT,也听说过BT对硬盘很伤,不能开多,而所谓伤害,和这里指的都是同一样东西,大量I/O导致磁盘出现碎片甚至出现磁盘坏道.

这里都是说些很实际的例子来说明问题了.

3.关于伪静态的坏处
当然犹如一篇文章的作者所说的

“如果流量稍大一些使用伪静态就出现CPU使用超负荷,我的同时在线300多人就挂了,而不使用伪静态的时候同时在线超500人都不挂,我的ISS数是1000”

确实是这样的,由于伪静态是用正则判断而不是真实地址,分辨到底显示哪个页面的责任也由直接指定转由CPU来判断了,所以CPU占有量的上升,确实是伪静态最大的弊病.

4.我们该如何做?

我们来总结一下.
1.使用真静态和假静态对SEO来说没有什么区别
2.使用真静态可能将导致硬盘损坏并将影响论坛性能
3.使用伪静态将占用一定量的CPU占有率,大量使用将导致CPU超负荷
4.最重要的一点,我们要静态是为了SEO

所以.
1.使用真静态的方法可以直接排除了,因为无论怎么生成,对硬盘来说都是很伤的.
2.既然真伪静态的效果一样,我们就可以选择伪静态了.
3.但是伪静态大量使用会照成CPU超负荷.
4.所以我们只要不大量使用就可以了.
5.既然静态只是给SEO看的,我们只需要伪静态给SEO就行了,不需要给用户使用.
6.所以我们只要在专门提供给SEO爬的Archiver中使用伪静态就可以了.
7.谢谢大家耐心看我写的文章.
8.有何不解的地方或是有不同的看法欢迎提出.

preg_replace只替换一次

<?php
function sst($result,$keys){
$len=substr_count($result,$keys);
for($i=1;$i<=$len;$i++){
$num=$i.”、”;
$result=preg_replace(“/$keys/”,$num,$result,1);
echo $result.”<br/>”;
}

return $result;
}

sst(“<xdw>十分士大夫发生发生<xdw>123544++;<xdw>545″,”<xdw>”);

?>

addslashes,mysql_real_escape_string ,mysql_escape_string的区别

本文介绍的是用 mysql_real_escape_string对用户提交数据进行整理处理和通过addslashes以及mysql_escape_string这3个类似的功能函数的区别。经过转义的数据可以直接插入到数据库中。

很好的说明了addslashes和mysql_real_escape_string的区别,虽然国内很多PHP coder仍在依靠addslashes防止SQL注入(包括我在内),我还是建议大家加强中文防止SQL注入的检查。addslashes的问题在于黑客可以用0xbf27来代替单引号,而addslashes只是将0xbf27修改为0xbf5c27,成为一个有效的多字节字符,其中的0xbf5c仍会被看作是单引号,所以addslashes无法成功拦截。

当然addslashes也不是毫无用处,它是用于单字节字符串的处理,多字节字符还是用mysql_real_escape_string吧。

另外对于php手册中get_magic_quotes_gpc的举例:
if (!get_magic_quotes_gpc()) {
$lastname = addslashes($_POST[‘lastname’]);
} else {
$lastname = $_POST[‘lastname’];
}
最好对magic_quotes_gpc已经开放的情况下,还是对$_POST[’lastname’]进行检查一下。

再说下mysql_real_escape_string和mysql_escape_string这2个函数的区别:
mysql_real_escape_string 必须在(PHP 4 >= 4.3.0 PHP 5)的情况下才能使用。否则只能用 mysql_escape_string ,两者的区别是:
mysql_real_escape_string 考虑到连接的当前字符集,而mysql_escape_string 不考虑。

总结一下:

addslashes() 是强行加;

mysql_real_escape_string() 会判断字符集,但是对PHP版本有要求;

mysql_escape_string不考虑连接的当前字符集。

mysql_real_escape_string()函数用于转义SQL语句中的特殊字符,该函数的语法格式如下:

string mysql_real_escape_string ( string $unescaped_string[, resource $link_identifier ] )

在上述语法中涉及到的参数说明如下。

unescaped_string:未转义的字符串。

link_identifier:MySQL的连接标识符。

mysql_real_escape_string()函数不转义”%” 和 “_”这两个符号。

使用函数mysql_real_escape_string()函数的示例代码如下:

代码23-19 光盘\codes\第23章\23.4\mysql_real_escape_string.php

<?php $connection=mysql_connect(“localhost”,”root”,”root”) ordie(“连接服务器失败”); $person= “Jone’s and Bobo’s teacher”; $escaped_person= mysql_real_escape_string($person); echo$escaped_person; ?>

上面代码的输出结果如图23-18所示。

图23-18 转义后的字符

Linux下的文件共享全攻略系列之三:主流FTP服务器Wu-ftpd入门指南

目前,研究者们开发了许多网络服务和协议来完成资源共享的功能。对于网络用户和管理员来说,他们希望得到免费和高效的服务,而这种需求的最好选择莫过于当前开源的操作系统Linux下的产品了。本专题从多个应用服务层面着重向读者们推荐几种实用的用于资源共享的技术及其软件。

本文是系列的第3篇文章,详细介绍FTP。专题的完整内容,请参见:

Linux下的文件共享服务全攻略 http://os.51cto.com/art/201010/231947.htm

 

 

Wu-ftpd是Internet上最流行的FTP守护程序。Wu-ftpd功能十分强大,可以构建多种类型FTP服务器。Wu-ftpd菜单可以帮助用户轻松地实现对FTP服务器的配置:支持构造安全方式的匿名FTP的访问,可以控制同时访问的用户的数量,限制可以允许访问的IP网段,并可以在一台主机上设置多个虚拟目录。Wu-ftpd有三种注册方式:匿名FTP、实际用户FTP以及guestFTP。匿名FTP使用用户名“anonymous”和一个email类型的口令进行注册。

Wu-ftpd发布较早。在最新版本(2.6.2)里,其已经对最为人担心的系统安全性问题做了完善的修正,因此还是Ftp Server中的主流。下列是Wu-ftpd的一些功能:

可对不同网域实行不同存取权限和可存取时段。用户在下载档案的同时,可自动实行压缩或解压工作。可记录FTP Server使用情形。可限定最多联机人数,以符合整体运作效能。显示相关讯息,让使用者了解接收状态。可将FTP Server暂停,便于系统维护。支持虚拟FTP主机(Virtual FTP Servers)。1、安装Wu-ftpd服务器

安装Wu-ftpd有两种方式,一种是安装RPM形式的发布包;另外一种方式是自己动手去编译生成。下面分别介绍这两种安装方式的步骤。

1.RPM包安装方式

该安装包可以在RPMfind上下载得到。以RPM包方式安装非常简单,只要执行下面简单的几个步骤就可以完成:

//将下载得到的rpm包存放在/tmp目录下#cp wu-ftpd-2.6.2-8.i386.rpm /tmp//切换目录#cd /tmp//进行安装#rpm -ivh wu-ftpd-2.6.2-8.i386.rpm

2.源代码安装方式

压缩的源代码可以在处得到。目前网上的最新版本为:wu-ftpd-2.6.2.tar,下面是安装步骤:

//将压缩的源代码拷贝到/usr/src目录下# cp wu-ftpd.2.6.2.tar.gz /usr/src//对压缩文档进行解压缩#tar xvfz wu-ftpd.2.6.2.tar.gz//切换目录#cd wu-ftpd-2.6.2//配置#./configure//编译#make#make install2、启动Wu-ftpd服务器

在安装好Wu-ftpd服务器后,就可以用默认配置启动使用该服务器了。通常来说,启动该服务器有两种方式:使用xinetd以及命令行启动。下面首先分别介绍这两种启动方式,然后通过例子说明使用该服务器的过程。

1.xinetd启动方式

使用该启动方式,只要在/etc/xinetd.d目录下配置wu-ftpd文件即可,如下步骤所示:

#vi wu-ftpd //使用vi编辑wu-ftpd文件//编辑内容如下# default: on /默认/系统启动时同时启动该服务器# description: The wu-ftpd FTP server serves FTP connections. It uses \# normal, unencrypted usernames and passwords for authentication.service ftp{disable = nosocket_type = streamwait = nouser = rootserver = /usr/sbin/in.ftpdserver_args = -l -alog_on_success += DURATION USERIDlog_on_failure += USERIDnice = 10}#service xinetd restart //重新启动xientd服务,以使改动生效

2.命令行方式启动

使用命令行启动该服务器非常简单,如下所示命令:

#/usr/sbin/ftpshut //首先关闭该服务#/usr/sbin/ftprestart //然后重新启动

接下来,我们将通过具体的例子说明Wu-ftpd服务器的使用方法。

 

3、使用Wu-ftpd服务器

本小节通过具体的例子来说明如何使用Wu-ftpd服务器。

(1)使用匿名用户登录服务器

该步骤使用用户名Anonymous进行FTP登录,密码可以随便输入,一般情况下Wu-FTP服务器都会通过,这也是大多数Wu-FTP服务器的默认登录方式。

#ftp 127.0.0.1Connected to 127.0.0.1 (127.0.0.1).220 aserver FTP server (Version wu-2.6.2) ready.Name (127.0.0.1:root): anonymous331 Guest login ok, send your complete e-mail address as password.Password:230 Guest login ok, access restrictions apply.

(2)浏览匿名用户登录到服务器的目录

该步骤测试使用匿名用户登录Wu-FTP服务器后的浏览情况,即匿名用户登录后能够看到的FTP服务器资源的视图。在一般情况下,匿名用户只具有非常有限的资源视图,因而级别较低。如果需要提升权限的话,需要针对匿名用户进行配置。

ftp> ls227 Entering Passive Mode (127,0,0,1,101,144)150 Opening ASCII mode data connection for directory listing.total 40d–x–x–x 2 root root 4096 Jun 13 2002 bind–x–x–x 2 root root 4096 Jul 22 2002 etcdrwxrwxrwx 10 14 50 4096 Oct 10 2003 incomingdrwxr-xr-x 2 root root 4096 Jun 13 2002 libdrwxrwxrwx 2 root 50 4096 Nov 8 2002 pub226 Transfer complete.ftp> cd pub250 CWD command successful.ftp> ls227 Entering Passive Mode (127,0,0,1,140,149)150 Opening ASCII mode data connection for directory listing.total 18008-rw-r–r– 1 root root 9203662 Oct 7 2002 stack.ots.20021006.tgz226 Transfer complete.

(3)测试建立目录权限,操作失败,匿名用户没有该权限

该步骤进一步测试匿名用户所具有的权限。通过此操作不难看到,在匿名用户建立目录时,服务器返回失败,进一步证明了匿名用户一般情况下只具有读的权限,而不具有写的权限。

ftp> mkdir super550 super: Permission denied on server. (Upload dirs)ftp> cd incoming550 incoming: No such file or directory.ftp> cd ..250 CWD command successful.ftp> ls227 Entering Passive Mode (127,0,0,1,164,206)150 Opening ASCII mode data connection for directory listing.total 40d–x–x–x 2 root root 4096 Jun 13 2002 bind–x–x–x 2 root root 4096 Jul 22 2002 etcdrwxrwxrwx 10 14 50 4096 Oct 10 2003 incomingdrwxr-xr-x 2 root root 4096 Jun 13 2002 libdrwxrwxrwx 2 root 50 4096 Nov 8 2002 pub226 Transfer complete.

(4)进入指定目录,准备测试下载文件功能

该步骤测试Wu-FTP服务器的下载文件功能。对于匿名用户来说,最常见的一个功能就是下载文件,从而说明FTP服务器的最大的功效就是文件和资源共享。

ftp> cd incoming250 CWD command successful.ftp> dir227 Entering Passive Mode (127,0,0,1,22,51)150 Opening ASCII mode data connection for directory listing.total 112936-rw-rw-rw- 1 14 50 47104 Aug 26 2002 1.rtf-rw-rw-rw- 1 14 50 4812 Aug 28 2002 LiveTri.zipdrwxrwxrwx 3 4095 root 4096 Dec 14 2002 RA-rw-rw-rw- 1 14 50 672 Oct 30 2002 a-rw-r–r– 1 root root 38754436 Oct 30 2002 linux-2.4.18.tar.gzdrwxrwxrwx 2 root root 4096 Nov 26 2002 packagedrwxrwxrwx 2 4095 root 4096 Jul 29 2002 public_module-rw-rw-rw- 1 14 50 1968255 Oct 30 2002 rfc2616.pdfdrwxrwxrwx 3 4095 root 4096 Aug 2 2002 sample_log-rw-r–r– 1 root root 6506 Jul 28 2002 sendpacket.tar.gzdrwxrwxr-x 11 510 510 4096 Oct 17 2002 stack-rw-rw-rw- 1 14 50 0 Jul 24 2002 tcpipdrwxrwxrwx 4 4095 root 4096 Aug 23 2002 temp-rw-rw-rw- 1 14 50 0 Aug 22 2002 test.doc226 Transfer complete. //如下操作说明下载文件test.doc操作成功ftp> get test.doclocal: test.doc remote: test.doc227 Entering Passive Mode (127,0,0,1,7,193)150 Opening ASCII mode data connection for test.doc (0 bytes).226 Transfer complete. //通过如下操作浏览下载到本地的文件,发现test.doc已经下载在其中ftp> !lschargen cvspserver daytime-udp echo-udp ntalk qmail-pop3 rexec rsh sgi_fam telnet time wu-ftpdchargen-udp daytime echo finger pop3 qmail-smtp rlogin rsync talk test.doc time-udpftp> put wu-ftpdlocal: wu-ftpd remote: wu-ftpd227 Entering Passive Mode (127,0,0,1,202,89)150 Opening ASCII mode data connection for wu-ftpd.226 Transfer complete.376 bytes sent in 0.00011 secs (3.3e+03 Kbytes/sec)

(5)测试删除权限,操作失败

最后一个步骤来测试匿名用户对于Wu-FTP服务器中共享资源的删除权限状况。实验证明,匿名用户一般不具有删除权限,否则会成为巨大的安全隐患,共享的资源随时都会有被删除的危险,因而需要对该权限实行禁用。

ftp> delete wu-ftpd553 wu-ftpd: Permission denied on server. (Delete)ftp> bye221-You have transferred 361 bytes in 2 files.221-Total traffic for this session was 1873 bytes in 2 transfers.221 Thank you for using the FTP service on aserver.

MYSQL 随机 抽取实现方法及效率分析

MYSQL的随机抽取实现方法。举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND() LIMIT 1。

代码如下:
请教怎么从数据库随机读出15条记录?
order by rand() limit 0,15
怎么从数据库随机读出所有记录?
order by rand()

 

但是,后来我查了一下MYSQL的官方手册,里面针对RAND()的提示大概意思就是,在ORDER BY从句里面不能使用RAND()函数,因为这样会导致数据列被多次扫描。但是在MYSQL 3.23版本中,仍然可以通过ORDER BY RAND()来实现随机。

但是真正测试一下才发现这样效率非常低。一个15万余条的库,查询5条数据,居然要8秒以上。查看官方手册,也说rand()放在ORDER BY 子句中会被执行多次,自然效率及很低。
You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times.
搜索Google,网上基本上都是查询max(id) * rand()来随机获取数据。
SELECT *
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id ASC LIMIT 5;

但是这样会产生连续的5条记录。解决办法只能是每次查询一条,查询5次。即便如此也值得,因为15万条的表,查询只需要0.01秒不到。

下面的语句采用的是JOIN,mysql的论坛上有人使用
SELECT *
FROM `table`
WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` )
ORDER BY id LIMIT 1;

我测试了一下,需要0.5秒,速度也不错,但是跟上面的语句还是有很大差距。总觉有什么地方不正常。

于是我把语句改写了一下。
SELECT * FROM `table`
WHERE id >= (SELECT floor(RAND() * (SELECT MAX(id) FROM `table`)))
ORDER BY id LIMIT 1;

这下,效率又提高了,查询时间只有0.01秒

最后,再把语句完善一下,加上MIN(id)的判断。我在最开始测试的时候,就是因为没有加上MIN(id)的判断,结果有一半的时间总是查询到表中的前面几行。
完整查询语句是:
SELECT * FROM `table`
WHERE id >= (SELECT floor( RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`)) + (SELECT MIN(id) FROM `table`)))
ORDER BY id LIMIT 1;

SELECT *
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`))+(SELECT MIN(id) FROM `table`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 1;

最后在php中对这两个语句进行分别查询10次,
前者花费时间 0.147433 秒
后者花费时间 0.015130 秒
看来采用JOIN的语法比直接在WHERE中使用函数效率还要高很多。