PHP下载远程文件类源码,带详细注释,还支持断点续传
程序主要是使用 HTTP 协议下载文件,HTTP1.1协议必须指定文档结束后关闭链接,否则读取文档时无法使用feof判断结束,可以有两种使用方法,具体请下载查看源码。
代码如下 | 复制代码 |
<?php /** * 下载远程文件类支持断点续传 */ class HttpDownload { private $m_url = ""; private $m_urlpath = ""; private $m_scheme = "http"; private $m_host = ""; private $m_port = "80"; private $m_user = ""; private $m_pass = ""; private $m_path = "/"; private $m_query = ""; private $m_fp = ""; private $m_error = ""; private $m_httphead = "" ; private $m_html = ""; /** * 初始化 */ public function PrivateInit($url){ $urls = ""; $urls = @parse_url($url); $this->m_url = $url; if(is_array($urls)) { $this->m_host = $urls["host"]; if(!empty($urls["scheme"])) $this->m_scheme = $urls["scheme"]; if(!empty($urls["user"])) $this->m_user = $urls["user"]; if(!empty($urls["pass"])) $this->m_pass = $urls["pass"]; if(!empty($urls["port"])) $this->m_port = $urls["port"]; if(!empty($urls["path"])) $this->m_path = $urls["path"]; $this->m_urlpath = $this->m_path; if(!empty($urls["query"])) { $this->m_query = $urls["query"]; $this->m_urlpath .= "?".$this->m_query; } } } /** * 打开指定网址 */ function OpenUrl($url) { #重设各参数 $this->m_url = ""; $this->m_urlpath = ""; $this->m_scheme = "http"; $this->m_host = ""; $this->m_port = "80"; $this->m_user = ""; $this->m_pass = ""; $this->m_path = "/"; $this->m_query = ""; $this->m_error = ""; $this->m_httphead = "" ; $this->m_html = ""; $this->Close(); #初始化系统 $this->PrivateInit($url); $this->PrivateStartSession(); } /** * 获得某操作错误的原因 */ public function printError() { echo "错误信息:".$this->m_error; echo "具体返回头:<br>"; foreach($this->m_httphead as $k=>$v) { echo "$k => $v <br>rn"; } } /** * 判别用Get方法发送的头的应答结果是否正确 */ public function IsGetOK() { if( ereg("^2",$this->GetHead("http-state")) ) { return true; } else { $this->m_error .= $this->GetHead("http-state")." - ".$this->GetHead("http-describe")."<br>"; return false; } } /** * 看看返回的网页是否是text类型 */ public function IsText() { if (ereg("^2",$this->GetHead("http-state")) && eregi("^text",$this->GetHead("content-type"))) { return true; } else { $this->m_error .= "内容为非文本类型<br>"; return false; } } /** * 判断返回的网页是否是特定的类型 */ public function IsContentType($ctype) { if (ereg("^2",$this->GetHead("http-state")) && $this->GetHead("content-type") == strtolower($ctype)) { return true; } else { $this->m_error .= "类型不对 ".$this->GetHead("content-type")."<br>"; return false; } } /** * 用 HTTP 协议下载文件 */ public function SaveToBin($savefilename) { if (!$this->IsGetOK()) return false; if (@feof($this->m_fp)) { $this->m_error = "连接已经关闭!"; return false; } $fp = fopen($savefilename,"w") or die("写入文件 $savefilename 失败!"); while (!feof($this->m_fp)) { @fwrite($fp,fgets($this->m_fp,256)); } @fclose($this->m_fp); return true; } /** * 保存网页内容为 Text 文件 */ public function SaveToText($savefilename) { if ($this->IsText()) { $this->SaveBinFile($savefilename); } else { return ""; } } /** * 用 HTTP 协议获得一个网页的内容 */ public function GetHtml() { if (!$this->IsText()) return ""; if ($this->m_html!="") return $this->m_html; if (!$this->m_fp||@feof($this->m_fp)) return ""; while(!feof($this->m_fp)) { $this->m_html .= fgets($this->m_fp,256); } @fclose($this->m_fp); return $this->m_html; } /** * 开始 HTTP 会话 */ public function PrivateStartSession() { if (!$this->PrivateOpenHost()) { $this->m_error .= "打开远程主机出错!"; return false; } if ($this->GetHead("http-edition")=="HTTP/1.1") { $httpv = "HTTP/1.1"; } else { $httpv = "HTTP/1.0"; } fputs($this->m_fp,"GET ".$this->m_urlpath." $httpvrn"); fputs($this->m_fp,"Host: ".$this->m_host."rn"); fputs($this->m_fp,"Accept: */*rn"); fputs($this->m_fp,"User-Agent: Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.2)rn"); #HTTP1.1协议必须指定文档结束后关闭链接,否则读取文档时无法使用feof判断结束 if ($httpv=="HTTP/1.1") { fputs($this->m_fp,"Connection: Closernrn"); } else { fputs($this->m_fp,"rn"); } $httpstas = fgets($this->m_fp,256); $httpstas = split(" ",$httpstas); $this->m_httphead["http-edition"] = trim($httpstas[0]); $this->m_httphead["http-state"] = trim($httpstas[1]); $this->m_httphead["http-describe"] = ""; for ($i=2;$i<count($httpstas);$i++) { $this->m_httphead["http-describe"] .= " ".trim($httpstas[$i]); } while (!feof($this->m_fp)) { $line = str_replace(""","",trim(fgets($this->m_fp,256))); if($line == "") break; if (ereg(":",$line)) { $lines = split(":",$line); $this->m_httphead[strtolower(trim($lines[0]))] = trim($lines[1]); } } } /** * 获得一个Http头的值 */ public function GetHead($headname) { $headname = strtolower($headname); if (isset($this->m_httphead[$headname])) { return $this->m_httphead[$headname]; } else { return ""; } } /** * 打开连接 */ public function PrivateOpenHost() { if ($this->m_host=="") return false; $this->m_fp = @fsockopen($this->m_host, $this->m_port, &$errno, &$errstr,10); if (!$this->m_fp){ $this->m_error = $errstr; return false; } else { return true; } } /** * 关闭连接 */ public function Close(){ @fclose($this->m_fp); } } #两种使用方法,分别如下: #打开网页 $httpdown = new HttpDownload(); $httpdown->OpenUrl("http://www.google.com.hk"); echo $httpdown->GetHtml(); $httpdown->Close(); #下载文件 $file = new HttpDownload(); # 实例化类 $file->OpenUrl("http://www.ti.com.cn/cn/lit/an/rust020/rust020.pdf"); # 远程文件地址 $file->SaveToBin("rust020.pdf"); # 保存路径及文件名 $file->Close(); # 释放资源 ?> |
phpinfo,可以看到session存储,可以使用files user memcache redis,使用数据库存储session的好处是较之文件存储,在大用户量下速度更快,性能更优,而且如果做分布式系统,肯定是需要使用数据库存储session的。这里总结下使用redis存储session的两种方式
使用mysql存储session大家应该使用过,session生命周期的原理其实就是session.gcprobability,session.gcdivisor这两个参数和最大生命时间决定的。每次php请求,有一定几率触发session的检测机制。我们使用session_setsavehandler,是可以重定义session的行为的。这里有两种方式实现redis存储session
代码实例1:
代码如下 | 复制代码 |
<?php |
代码实例2:
代码如下 | 复制代码 |
<?php class RedisSessionHandler{ public $ttl = 1800; // 30 minutes default protected $db; protected $prefix; public function __construct($db, $prefix = 'PHPSESSID1:',$time=1800) { $this->db = $db; $this->prefix = $prefix; $this->ttl = $time; } function _open() { // } function _close() { $this->db = null; unset($this->db); } function _read($id) { $id = $this->prefix . $id; $sessData = $this->db->get($id); $this->db->expire($id, $this->ttl); return $sessData; } function _write($id, $data) { $id = $this->prefix . $id; $this->db->set($id, $data); $this->db->expire($id, $this->ttl); } function _destroy($id) { $this->db->del($this->prefix . $id); } function _clean($max) { // } } $redis = new Redis(); $redis->connect('127.0.0.1',6379); $redis->select(1); $SESSION_ID_PREFIX = 'RSID:'; $SESSION_MAX_TIME = 1440; ini_set('session.gc_maxlifetime',$SESSION_MAX_TIME); $sessHandler = new RedisSessionHandler($redis,$SESSION_ID_PREFIX,$SESSION_MAX_TIME); session_set_save_handler( array($sessHandler, '_open'), array($sessHandler, '_close'), array($sessHandler, '_read'), array($sessHandler, '_write'), array($sessHandler, '_destroy'), array($sessHandler, '_clean') ); session_start(); echo session_id(); echo $_SESSION['name']='zhangcunchao'; |
> 第一种方式比较简单,但是无法选择库号,并且session_id的前缀信息比较难以控制,但是此方法也可以直接修改php配置文件,使所有程序的session使用redis
> 第二种方式相对麻烦一点,但是使用起来比方方便
> 网上有说并发一致性问题,所有的哈希算法肯定都会有这样的问题,不过可以通过ip前缀哈希组合来一定程度解决
Ajax多图片上传效果界面
我们在页面上放置一个form表单,使用post提交到后台php处理程序upload.php,注意enctype属性设置要支持文件上传。#preview用来显示上传完毕后的图片。关于css样式设置本文不加说明,请参照下载包的源码。
代码如下 | 复制代码 |
<form id="imageform" method="post" enctype="multipart/form-data" action="upload.php"> <div id="up_status" style="display:none"><img src="loader.gif" alt="uploading"/></div> <div id="up_btn" class="btn"> <span>添加图片</span> <input id="photoimg" type="file" name="photoimg"> </div> </form> <p>最大100KB,支持jpg,gif,png格式。</p> <div id="preview"></div> |
本实例基于jQuery,因此必须在页面中载入jquery库以及jquery.wallform.js。
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="jquery.wallform.js"></script>
当点击按钮“添加图片”后,弹出选择文件对话框,选择要上传的图片后,触发change事件。然后表单#imageform调用jquery.wallform.js的ajaxForm()方法,将表单数据提交给后台PHP处理,并根据返回结果处理页面元素的展示。如果上传成功,图片会一张张排列显示在页面上。关于ajaxForm()的使用可以参照本站文章:Ajax表单提交插件jqery form。
代码如下 | 复制代码 |
$(function(){ $('#photoimg').die('click').live('change', function(){ var status = $("#up_status"); var btn = $("#up_btn"); $("#imageform").ajaxForm({ target: '#preview', beforeSubmit:function(){ status.show(); btn.hide(); }, success:function(){ status.hide(); btn.show(); }, error:function(){ status.hide(); btn.show(); } }).submit(); }); }); |
upload.php处理图片上传,并将上传好的图片保存在uploads/目录,注意该目录要有写权限。首先需要检测是否为POST方式提交,然后判断图片格式、图片大小是否符合要求,然后使用move_uploaded_file()上传图片,并将图片重命名,格式为:time().rand(100,999)。
代码如下 | 复制代码 |
$path = "uploads/"; $extArr = array("jpg", "png", "gif"); if(isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST"){ $name = $_FILES['photoimg']['name']; $size = $_FILES['photoimg']['size']; if(empty($name)){ echo '请选择要上传的图片'; exit; } $ext = extend($name); if(!in_array($ext,$extArr)){ echo '图片格式错误!'; exit; } if($size>(100*1024)){ echo '图片大小不能超过100KB'; exit; } $image_name = time().rand(100,999).".".$ext; $tmp = $_FILES['photoimg']['tmp_name']; if(move_uploaded_file($tmp, $path.$image_name)){ echo '<img src="'.$path.$image_name.'" class="preview">'; }else{ echo '上传出错了!'; } exit; } //获取文件类型后缀 function extend($file_name){ $extend = pathinfo($file_name); $extend = strtolower($extend["extension"]); return $extend; } |
1) time() 获取当前的系统时间戳
int time(void) :
返回当前的 Unix 时间戳 (返回自从 Unix 纪元(格林威治时间 1970 年 1 月 1 日 00:00:00)到当前时间的秒数。 )
自 PHP 5.1 起在 $_SERVER['REQUEST_TIME'] 中保存了发起该请求时刻的时间戳。
$_SERVER["REQUEST_TIME"] :The timestamp of the start of the request. Available since PHP 5.1.0. 一看解释就都明白了
2) $_SERVER["REQUEST_TIME"] 得到请求开始时的时间戳
实例代码:
代码如下 | 复制代码 |
<?php date_default_timezone_set('PRC'); sleep(5);//php脚本睡5秒 echo date('Y-m-d H:i:s',time());//获取当前系统时间的时间戳 echo '<hr />'; echo date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']);//得到请求此php脚本时的时间戳 ?> |
输出结果截图如下:
结论:
因为sleep(5)睡了5秒,之后用time()获取系统的时间戳,$_SERVER['REQUEST_TIME']则记录了发起此请求时刻的时间戳。所以$_SERVER['REQUEST_TIME']比用time()获取的时间戳早5秒
<?php include 'ganon.php'; $html = file_get_dom('http://www.111cn.net/'); foreach($html('div[class="focus"]') as $element) { echo $element->class, "<br>n"; } ?>
<?php include 'phpQuery/phpQuery.php'; phpQuery::newDocumentFile('http://www.111cn.net/'); $artlist = pq("article"); foreach($artlist as $title){ echo pq($title)->find('h2')->html()."<br/>"; } ?>
文档: http://simplehtmldom.sourceforge.net/manual.htm
<?php include 'simple_html_dom.php'; //使用url和file都可以创建DOM $html = file_get_html('http://www.111cn.net/'); //找到所有图片 // foreach($html->find('img') as $element) // echo $element->src . '<br>'; //找到所有链接 foreach($html->find('a') as $element) echo $element->href . '<br>'; ?>
<?php include("Snoopy.class.php"); $url = "http://www.111cn.net"; $snoopy = new Snoopy; $snoopy->fetch($url); //获取所有内容 echo $snoopy->results; //显示结果 // echo $snoopy->fetchtext ;//获取文本内容(去掉html代码) // echo $snoopy->fetchlinks($url) ;//获取链接 // $snoopy->fetchform ;//获取表单 ?>
如果编写能力ok,可以手写一个网页爬虫,实现网页抓取。网上有千篇一律的介绍此方法的文章,LZ就不赘述了。有兴趣了解的,可以百度 php 网页抓取。
七、开源爬虫软件汇总
发语言
|
软件名称
|
软件介绍
|
许可证
|
Java
|
Arachnid
|
微型爬虫框架,含有一个小型HTML解析器
|
GPL
|
crawlzilla
|
安装简易,拥有中文分词功能
|
Apache2
|
|
Ex-Crawler
|
由守护进程执行,使用数据库存储网页信息
|
GPLv3
|
|
Heritrix
|
严格遵照robots文件的排除指示和META robots标签
|
LGPL
|
|
heyDr
|
轻量级开源多线程垂直检索爬虫框架
|
GPLv3
|
|
ItSucks
|
提供swing GUI操作界面
|
不详
|
|
jcrawl
|
轻量、性能优良,可以从网页抓取各种类型的文件
|
Apache
|
|
JSpider
|
功能强大,容易扩展
|
LGPL
|
|
Leopdo
|
包括全文和分类垂直搜索,以及分词系统
|
Apache
|
|
MetaSeeker
|
网页抓取、信息提取、数据抽取工具包,操作简单
|
不详
|
|
Playfish
|
通过XML配置文件实现高度可定制性与可扩展性
|
MIT
|
|
Spiderman
|
灵活、扩展性强,微内核+插件式架构,通过简单的配置就可以完成数据抓取,无需编写一句代码
|
Apache
|
|
webmagic
|
功能覆盖整个爬虫生命周期,使用Xpath和正则表达式进行链接和内容的提取
|
Apache
|
|
Web-Harvest
|
运用XSLT、XQuery、正则表达式等技术来实现对Text或XML的操作,具有可视化的界面
|
BSD
|
|
WebSPHINX
|
由两部分组成:爬虫工作平台和WebSPHINX类包
|
Apache
|
|
YaCy
|
基于P2P的分布式Webseo/seo.html" target="_blank">搜索引擎
|
GPL
|
|
Python
|
QuickRecon
|
具有查找子域名名称、收集电子邮件地址并寻找人际关系等功能
|
GPLv3
|
PyRailgun
|
简洁、轻量、高效的网页抓取框架
|
MIT
|
|
Scrapy
|
基于Twisted的异步处理框架,文档齐全
|
BSD
|
|
C++
|
hispider
|
支持多机分布式下载, 支持网站定向下载
|
BSD
|
larbin
|
高性能的爬虫软件,只负责抓取不负责解析
|
GPL
|
|
Methabot
|
经过速度优化、可抓取WEB、FTP及本地文件系统
|
不详
|
|
Methanol
|
模块化、可定制的网页爬虫,速度快
|
不详
|
|
C#
|
NWebCrawler
|
统计信息、执行过程可视化
|
GPLv2
|
Sinawler
|
国内第一个针对微博数据的爬虫程序,功能强大
|
GPLv3
|
|
spidernet
|
以递归树为模型的多线程web爬虫程序,支持以GBK (gb2312)和utf8编码的资源,使用sqlite存储数据
|
MIT
|
|
Web Crawler
|
多线程,支持抓取PDF/DOC/EXCEL等文档来源
|
LGPL
|
|
网络矿工
|
功能丰富,毫不逊色于商业软件
|
BSD
|
|
PHP
|
OpenWebSpider
|
开源多线程网络爬虫,有许多有趣的功能
|
不详
|
PhpDig
|
适用于专业化强、层次更深的个性化搜索引擎
|
GPL
|
|
Snoopy
|
具有采集网页内容、提交表单功能
|
GPL
|
|
ThinkUp
|
采集推特、脸谱等社交网络数据的社会媒体视角引擎,可进行交互分析并将结果以可视化形式展现
|
GPL
|
|
微购
|
可采集淘宝、京东、当当等300多家电子商务数据
|
GPL
|
|
ErLang
|
Ebot
|
可伸缩的分布式网页爬虫
|
GPLv3
|
Ruby
|
Spidr
|
可将一个或多个网站、某个链接完全抓取到本地
|
MIT
|
相关文章
- 下面小编来给大家演示几个php操作zip文件的实例,我们可以读取zip包中指定文件与删除zip包中指定文件,下面来给大这介绍一下。 从zip压缩文件中提取文件 代...2016-11-25
Jupyter Notebook读取csv文件出现的问题及解决
这篇文章主要介绍了JupyterNotebook读取csv文件出现的问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2023-01-06- 有时我们接受或下载到的PSD文件打开是空白的,那么我们要如何来解决这个 问题了,下面一聚教程小伙伴就为各位介绍Photoshop打开PSD文件空白解决办法。 1、如我们打开...2016-09-14
- 这篇文章主要介绍了解决python 使用openpyxl读写大文件的坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-13
- 这篇文章主要介绍了C#实现HTTP下载文件的方法,包括了HTTP通信的创建、本地文件的写入等,非常具有实用价值,需要的朋友可以参考下...2020-06-25
- 这篇文章主要为大家详细介绍了SpringBoot实现excel文件生成和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-09
- C#使用System.IO中的文件操作方法在Windows系统中处理本地文件相当顺手,这里我们还总结了在Oracle中保存文件的方法,嗯,接下来就来看看整理的C#操作本地文件及保存文件到数据库的基本方法总结...2020-06-25
php无刷新利用iframe实现页面无刷新上传文件(1/2)
利用form表单的target属性和iframe 一、上传文件的一个php教程方法。 该方法接受一个$file参数,该参数为从客户端获取的$_files变量,返回重新命名后的文件名,如果上传失...2016-11-25- 要替换字符串中的内容我们只要利用php相关函数,如strstr,str_replace,正则表达式了,那么我们要替换目录所有文件的内容就需要先遍历目录再打开文件再利用上面讲的函数替...2016-11-25
- 又码了一个周末的代码,这次在做一些关于文件上传的东西。(PHP UPLOAD)小有收获项目是一个BT种子列表,用户有权限上传自己的种子,然后配合BT TRACK服务器把种子的信息写出来...2016-11-25
- 今天小编在这里就来给photoshop的这一款软件的使用者们来说下AI源文件转photoshop图像变模糊问题的解决教程,各位想知道具体解决方法的使用者们,那么下面就快来跟着小编...2016-09-14
- 这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
- 步骤:Window -> PHP -> Editor -> Templates,这里可以设置(增、删、改、导入等)管理你的模板。新建文件注释、函数注释、代码块等模板的实例新建模板,分别输入Name、Description、Patterna)文件注释Name: 3cfileDescriptio...2013-10-04
- 本篇文章主要说明的是与php文件上传的相关配置的知识点。PHP文件上传功能配置主要涉及php.ini配置文件中的upload_tmp_dir、upload_max_filesize、post_max_size等选项,下面一一说明。打开php.ini配置文件找到File Upl...2015-10-21
ant design中upload组件上传大文件,显示进度条进度的实例
这篇文章主要介绍了ant design中upload组件上传大文件,显示进度条进度的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-29- 这篇文章主要介绍了C#使用StreamWriter写入文件的方法,涉及C#中StreamWriter类操作文件的相关技巧,需要的朋友可以参考下...2020-06-25
- 举一个案例:复制代码 代码如下:<?phpclass Downfile { function downserver($file_name){$file_path = "./img/".$file_name;//转码,文件名转为gb2312解决中文乱码$file_name = iconv("utf-8","gb2312",$file_name...2014-06-07
- 这篇文章主要介绍了C#路径,文件,目录及IO常见操作,较为详细的分析并汇总了C#关于路径,文件,目录及IO常见操作,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 通常php.ini的位置在:复制代码 代码如下:/etc目录下或/usr/local/lib目录下。如果你还是找不到php.ini或者找到了php.ini修改后不生效(其实是没找对),请使用如下办法:1.新建php文件,写入如下代码复制代码 代码如下:<?phpe...2014-05-31
- 分享给大家php判断上传文件类型的方法,大家一起学习学习。/** * 读取文件前几个字节 判断文件类型 * @return String */ function checkTitle($filename){ $file=fopen($filename, "rb"); $bin=fread($file, 2); /...2015-10-21