首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
135 阅读
2
php接口优化 使用curl_multi_init批量请求
129 阅读
3
2024年备考系统架构设计师
102 阅读
4
《从菜鸟到大师之路 ElasticSearch 篇》
101 阅读
5
PHP 文件I/O
89 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
785
篇文章
累计收到
4
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
785
篇与
的结果
2023-08-04
编写PHP代码总结
编写PHP代码总结1- 编写模块化代码良好的PHP代码应该是模块化代码。PHP的面向对象的编程功能是一些特别强大的工 具,可以把你的应用程序分解成函数或方法。你应该尽可能多的从你的应用程序的服务器端分开前端的HTML/CSS/JavaScript代码。你也可以在 任何PHP框架上遵循MVC(模型-视图-控制器)模式。2- 代码编写规范良好的PHP代码应该有一套完整的代码编写规范。通过对变量和函数的命名,统一的方法访问数据库和对错误的处理,以及同样的代码缩进方式等来达到编程规范,这样可以使你的代码更具可读性。3- 编写可移植代码良好的PHP代码应该是可移植的。你可以使用php的现有功能,如魔术引号和短标签。试着了解你的需求,然后通过适应PHP特性来编写代码让代码独立、可移植。4- 编写安全代码良 好的PHP代码应该是安全的。PHP5提供了出色的性能和灵活性。但是安全问题完全在于开发人员。对于一个专业的PHP开发人员来说,深入理解重大安全漏 洞是至关重要的,如:跨站点脚本(XSS)、跨站请求伪造(CSRF)、代码注入漏洞、字符编码漏洞。通过使用PHP的特殊功能和函数, 如:mysql_real_escape_string等等,你可以编写出安全的代码。5- 代码注释代码注释是代码的重要组成部分。通过代码注释可以知道该变量或函数是做什么的,这将在今后的代码维护中十分有用。6- 避免短标签把所有用到短标签的替换成完整的PHP标签。7- 使用单引号代替双引号字符串始终使用单引号代替双引号,以避免PHP搜索字符串内的变量导致的性能下降。 用单引号代替双引号来包含字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会8- 转义字符串输出使用ENT_QUOTES作参数传递给htmlspecialchars函数,以确保单引号(')也转换成HTML实体,这是一个好习惯。9- 使用逗号分隔字符串输出通过echo语句输出使用逗号(,)分隔的字符串,要比使用字符串连接操作符(.)的性能更好。10- 输出前检查传来的值输出前检查传过来的值$_GET['query']。使用isset或empty函数,可以用来检查变量是否为null值。11- 其他如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍。$row['id'] 的速度是$row[id]的7倍。echo 比 print 快,并且使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接,比如echo $str1,$str2。在执行for循环之前确定最大循环数,不要每循环一次都计算最大值,最好运用foreach代替。注销那些不用的变量尤其是大数组,以便释放内存。尽量避免使用__get,__set,__autoload。require_once()代价昂贵。include文件时尽量使用绝对路径,因为它避免了PHP去include_path里查找文件的速度,解析操作系统路径所需的时间会更少。如果你想知道脚本开始执行(译注:即服务器端收到客户端请求)的时刻,使用$_SERVER['REQUEST_TIME']要好于time()。函数代替正则表达式完成相同功能。str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍。如果一个字符串替换函数,可接受数组或字符作为参数,并且参数长度不太长,那么可以考虑额外写一段替换代码,使得每次传递参数是一个字符,而不是只写一行代码接受数组作为查询和替换的参数。使用选择分支语句(译注:即switch case)好于使用多个if,else if语句。用@屏蔽错误消息的做法非常低效,极其低效。打开apache的mod_deflate模块,可以提高网页的浏览速度。数据库连接当使用完毕时应关掉,不要用长连接。错误消息代价昂贵。在方法中递增局部变量,速度是最快的。几乎与在函数中调用局部变量的速度相当。递增一个全局变量要比递增一个局部变量慢2倍。递增一个对象属性(如:$this->prop++)要比递增一个局部变量慢3倍。递增一个未预定义的局部变量要比递增一个预定义的局部变量慢9至10倍。仅定义一个局部变量而没在函数中调用它,同样会减慢速度(其程度相当于递增一个局部变量)。PHP大概会检查看是否存在全局变量。方法调用看来与类中定义的方法的数量无关,因为我(在测试方法之前和之后都)添加了10个方法,但性能上没有变化。派生类中的方法运行起来要快于在基类中定义的同样的方法。调用带有一个参数的空函数,其花费的时间相当于执行7至8次的局部变量递增操作。类似的方法调用所花费的时间接近于15次的局部变量递增操作。Apache解析一个PHP脚本的时间要比解析一个静态HTML页面慢2至10倍。尽量多用静态HTML页面,少用脚本。除非脚本可以缓存,否则每次调用时都会重新编译一次。引入一套PHP缓存机制通常可以提升25%至100%的性能,以免除编译开销。尽量做缓存,可使用memcached。memcached是一款高性能的内存对象缓存系统,可用来加速动态Web应用程序,减轻数据库负载。对运算码 (OP code)的缓存很有用,使得脚本不必为每个请求做重新编译。当操作字符串并需要检验其长度是否满足某种要求时,你想当然地会使用strlen()函数。此函数执行起来相当快,因为它不做任何计算,只返回在 zval 结构(C的内置数据结构,用于存储PHP变量)中存储的已知字符串长度。但是,由于strlen()是函数,多多少少会有些慢,因为函数调用会经过诸多步 骤,如字母小写化(译注:指函数名小写化,PHP不区分函数名大小写)、哈希查找,会跟随被调用的函数一起执行。在某些情况下,你可以使用isset() 技巧加速执行你的代码。 (举例如下) if (strlen($foo) < 5) { echo 'Foo is too short'; } (与下面的技巧做比较) if (!isset($foo[5])) { echo 'Foo is too short'; }调用isset()恰巧比strlen()快,因为与后者不同的是,isset()作为一种语言结构,意味着它的执行不需要函数查找和字母小写化。也就是说,实际上在检验字符串长度的顶层代码中你没有花太多开销。当执行变量$i的递增或递减时,$i++会比++$i慢一些。这种差异是PHP特有的,并不适用于其他语言,所以请不要修改你的C或Java代码 并指望它们能立即变快,没用的。++$i更快是因为它只需要3条指令(opcodes),$i++则需要4条指令。后置递增实际上会产生一个临时变量,这 个临时变量随后被递增。而前置递增直接在原值上递增。这是最优化处理的一种,正如Zend的PHP优化器所作的那样。牢记这个优化处理不失为一个好主意, 因为并不是所有的指令优化器都会做同样的优化处理,并且存在大量没有装配指令优化器的互联网服务提供商(ISPs)和服务器。并不是事必面向对象(OOP),面向对象往往开销很大,每个方法和对象调用都会消耗很多内存。并非要用类实现所有的数据结构,数组也很有用。不要把方法细分得过多,仔细想想你真正打算重用的是哪些代码?当你需要时,你总能把代码分解成方法。尽量采用大量的PHP内置函数。如果在代码中存在大量耗时的函数,你可以考虑用C扩展的方式实现它们。评估检验(profile)你的代码。检验器会告诉你,代码的哪些部分消耗了多少时间。Xdebug调试器包含了检验程序,评估检验总体上可以显示出代码的瓶颈。mod_zip可作为Apache模块,用来即时压缩你的数据,并可让数据传输量降低80%。在可以用file_get_contents替代file、fopen、feof、fgets等系列方法的情况下,尽量用file_get_contents,因为他的效率高得多!但是要注意file_get_contents在打开一个URL文件时候的PHP版本问题;尽量的少进行文件操作,虽然PHP的文件操作效率也不低的;优化Select SQL语句,在可能的情况下尽量少的进行Insert、Update操作(在update上,我被恶批过);尽可能的使用PHP内部函数(但是我却为了找个PHP里面不存在的函数,浪费了本可以写出一个自定义函数的时间,经验问题啊!);循环内部不要声明变量,尤其是大变量:对象(这好像不只是PHP里面要注意的问题吧?);多维数组尽量不要循环嵌套赋值;在可以用PHP内部字符串操作函数的情况下,不要用正则表达式;foreach效率更高,尽量用foreach代替while和for循环;“用i+=1代替i=i+1。符合c/c++的习惯,效率还高”;对global变量,应该用完就unset()掉;
2023年08月04日
7 阅读
0 评论
0 点赞
2023-08-04
超快速php入门
超快速php入门目前学习php的好资料多如牛毛,但是很多php学习者还是丈二和尚摸不着头脑,不知从何下手。学了一段时间之后总感觉进步不快。我们把这种现象称之为:还没有入门,也就是还没有找到学习的门路。一般需要一个简单而又快速的提醒。本人觉得该php快速入门能够最有效的点醒正在迷惑中的广大好友。祝你学习愉快。1、嵌入方法:类似ASP的<%,PHP可以是<?php或者是<?,结束符号是?>,当然您也可以自己指定。2、引用文件:引用文件的方法有两种:require 及 include。require 的使用方法如 require(”MyRequireFile.php”); 。这个函数通常放在 PHP 程序的最前面,PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部份。常用的函数,亦可以这个方法将它引入网页中。include 使用方法如 include(”MyIncludeFile.php”); 。这个函数一般是放在流程控制的处理部分中。PHP 程序网页在读到 include 的文件时,才将它读进来。这种方式,可以把程序执行时的流程简单化。3、注释方法:<?phpecho “这是第一种例子。n” ; // 本例是 C 语法的注释echo “这是第二种例子。n” ;echo “这是第三种例子。n” ; # 本例使用 UNIX Shell 语法注释?>4、变量类型:$mystring = “我是字符串” ;$NewLine = “换行了n” ;$int1 = 38 ;$float1 = 1.732 ;$float2 = 1.4E 2 ;$MyArray1 = array( “子” , “丑” , “寅” , “卯” );这里引出两个问题,首先PHP变量以$开头,第二PHP语句以;结尾,可能ASP程序员会不适应。这两个遗漏也是程序上大多错误所在。5、运算符号:数学运算: 符号 意义加法运算减法运算乘法运算/ 除法运算% 取余数累加– 递减字符串运算:运算符号只有一个,就是英文的句号。它可以将字符串连接起来,变成合并的新字符串。类似ASP中的&<?$a = “PHP 4″ ;$b = “功能强大” ;echo $a.$b;?>这里也引出两个问题,首先PHP中输出语句是echo,第二类似ASP中的<%=变量%>,PHP中也可以<?=变量? >。逻辑运算:符号 意义< 小于大于<= 小于或等于= 大于或等于== 等于!= 不等于&& 而且 (And)and 而且 (And)|| 或者 (Or)or 或者 (Or)xor 异或 (Xor)! 不 (Not)php的流程控制1、if..else 循环有三种结构第一种是只有用到 if 条件,当作单纯的判断。解释成 “若发生了某事则怎样处理”。语法如下:if (expr) { statement }其中的 expr 为判断的条件,通常都是用逻辑运算符号当判断的条件。而 statement 为符合条件的执行部分程序,若程序只有一行,可以省略大括号 {}。范例:本例省略大括号。<?phpif ($state==1)echo “哈哈” ;?>这里特别注意的是,判断是否相等是==而不是=,ASP程序员可能常犯这个错误,= 是赋值。范例:本例的执行部分有三行,不可省略大括号。<?phpif ($state==1) {echo “哈哈 ;echo “” ;}?>第两种是除了 if 之外,加上了 else 的条件,可解释成 “若发生了某事则怎样处理,否则该如何解决”。语法如下if (expr) { statement1 } else { statement2 } 范例:上面的例子来修改成更完整的处理。其中的 else 由于只有一行执行的指令,因此不用加上大括号。<?phpif ($state==1) {echo “哈哈” ;echo “”;}else{echo “呵呵”;echo “”;}?>第三种就是递归的 if..else 循环,通常用在多种决策判断时。它将数个 if..else 拿来合并运用处理。直接看下面的例子<?phpif ( $a > $b ) {echo “a 比 b 大” ;} elseif ( $a == $b ) {echo “a 等于 b” ;} else {echo “a 比 b 小” ;}?>上例只用二层的 if..else 循环,用来比较 a 和 b 两个变量。实际要使用这种递归 if..else 循环时,请小心使用,因为太多层的循环容易使设计的逻辑出问题,或者少打了大括号等,都会造成程序出现莫名其妙的问题。2、 for 循环就单纯只有一种,没有变化,它的语法如下for (expr1; expr2; expr3) { statement }其 中的 expr1 为条件的初始值。expr2 为判断的条件,通常都是用逻辑运算符号 (logical operators) 当判断的条件。expr3 为执行 statement 后要执行的部份,用来改变条件,供下次的循环判断,如加一..等等。而 statement 为符合条件的执行部分程序,若程序只有一行,可以省略大括号 {}。下例是用 for 循环写的的例子。<?phpfor ( $i = 1 ; $i <= 10 ; $i ) {echo “这是第”.$i.”次循环” ;}?>3、 switch 循环,通常处理复合式的条件判断,每个子条件,都是 case 指令部分。在实作上若使用许多类似的 if 指令,可以将它综合成 switch 循环。语法如下switch (expr) { case expr1: statement1; break; case expr2: statement2; break; default: statementN; break; }其中的 expr 条件,通常为变量名称。而 case 后的 exprN,通常表示变量值。冒号后则为符合该条件要执行的部分。注意要用 break 跳离循环。<?phpswitch ( date ( “D” )) {case “Mon” :echo “今天星期一” ;break;case “Tue” :echo “今天星期二” ;break;case “Wed” :echo “今天星期三” ;break;case “Thu” :echo “今天星期四” ;break;case “Fri” :echo “今天星期五” ;break;default:echo “今天放假” ;break;}?>这里需要注意的是break;别遗漏了,default,省略是可以的。很明显的,上述的例子用 if 循环就很麻烦了。当然在设计时,要将出现机率最大的条件放在最前面,最少出现的条件放在最后面,可以增加程序的执行效率。上例由于每天出现的机率相同,所以不用注意条件的顺序。构建数据库在ASP中,如果是ACCESS数据库你可以直接打开ACCESS来编辑MDB文件,如果是 SQL SERVER你可以打开企业管理器来编辑SQL SERVER数据库,但是在PHP中,MY SQL的命令行编辑可能会令初学者感到很麻烦,不要紧,你下载一个PHPMYADMIN安装一下,以后建立编辑数据库可以靠它了。下面说一下它的使用。进入了phpmyadmin后,我们首先需要建立一个数据库,Language (*) 这里选择中文简体,然后在左边的创建一个新的数据库这里填写数据库名字,点击创建即可。然后在左边下拉菜单中选择那个已经创建的数据库。在下面的在数据库 shop 中创建一个新表 :名字 :字段数 :中填写表名字和大致你认为的字段数(不够或者多了都不要紧,以后可以再添加或者缺省),按执行。然后就可以开始建立表了。第一栏是字段的名字;第二栏选择字段类型:我们常用的是以下几个:1)VARCHAR,文本类型2)INT,整数类型3)FLOAT,浮点数类型4)DATE,日期型5)大家或许会问,自动添加的ID在哪里?这个只要选择INT类型,在后面的额外中选择 auto_increment 就可以了。建立了表以后,可以在左边看到你建立的表,点击以后,你可以:1)按右边的结构:查看修改表结构2)按右边的浏览:查看表中的数据3)按右边的SQL:运行SQL语句4)按右边的插入:插入一行记录5)按右边的清空:删除表中所有记录6)按右边的删除:删除表还有一个很重要的功能就是导入和导出,当我们本机做好了程序和数据库的时候,需要在服务器上也有一个本地镜像,如果是ASP的ACCESS简单了,直接上传 MDB文件即可,如果是SQL SERVER也可以连接远端服务器进行导入。那么MY SQL中你可以导出所有的SQL语句,到了远端服务器的PHPMYADMIN上,创建数据库后按SQL,粘帖你刚才复制下来的所有本级生成的SQL语句即可。学会连接数据库PHP简直就是一个函数库,丰富的函数使PHP的某些地方相当简单。建议大家down一本PHP的函数手册,总用的到。我这里就简单说一下连接MYSQL数据库。1、mysql_connect打开 MySQL 服务器连接。语法: int mysql_connect(string [hostname] [:port], string [username], string [password]); 返回值: 整数本 函数建立与 MySQL 服务器的连接。其中所有的参数都可省略。当使用本函数却不加任何参数时,参数 hostname 的默认值为 localhost、参数 username 的默认值为 PHP 执行行程的拥有者、参数 password 则为空字符串 (即没有密码)。而参数 hostname 后面可以加冒号与端口号,代表使用哪个端口与 MySQL 连接。当然在使用数据库时,早点使用 mysql_close() 将连接关掉可以节省资源。2、 mysql_select_db选择一个数据库。语法: int mysql_select_db(string database_name, int [link_identifier]); 返回值: 整数本函数选择 MySQL 服务器中的数据库以供之后的资料查询作业 (query) 处理。成功返回 true,失败则返回 false。最简单的例子就是:$conn=mysql_connect (”127.0.0.1″, “”, “”);mysql_select_db(”shop”);连接机MY SQL数据库,打开SHOP数据库。在实际应用中应当加强点错误判断。读取数据先看两个函数:1、mysql_query送出一个 query 字符串。 语法: int mysql_query(string query, int [link_identifier]); 返回值: 整数本 函数送出 query 字符串供 MySQL 做相关的处理或者执行。若没有指定 link_identifier 参数,则程序会自动寻找最近打开的 ID。当 query 查询字符串是 UPDATE、INSERT 及 DELETE 时,返回的可能是 true 或者 false;查询的字符串是 SELECT 则返回新的 ID 值,当返回 false 时,并不是执行成功但无返回值,而是查询的字符串有错误。2、mysql_fetch_object 返回类资料。 语法: object mysql_fetch_object(int result, int [result_typ]); 返回值: 类本函数用来将查询结果 result 拆到类变量中。若 result 没有资料,则返回 false 值。看一个简单的例子:<?$exec=”select * from user”;$result=mysql_query($exec);while($rs=mysql_fetch_object($result)){echo “username:”.$rs->username.””;}?>当然,表user中有一个username的字段,这就类似asp中的<%exec=”select * from user”set rs=server.createobject(”adodb.recordset”)rs.open exec,conn,1,1do while not rs.eofresponse.write “username:”&rs(”username”)&””rs.movenextloop%>当然先要连接数据库,一般我们 require_once(’conn.php’);而conn.php里面就是上一次说的连接数据库的代码。添加删除修改数据mysql_query($exec);单这个语句就可以执行所有的操作了,不同的就是$exec这个sql语句添加:$exec=”insert into tablename (item1,item2) values (’”.$_POST['item1'].”‘,”.$_POST['item1'].”)”;删除:$exec=”delete from tablename where…”;修改:$exec=”update tablename set item1=’”.$_POST['item1'].”‘ where …”;说到这里就要说一下表单和php变量传递,如果表单中的一个 表单以POST提交的,那么处理表单文件就可以用$_POST['item1']得到变量值,同样以GET提交的就是$_GET['item1']是不是很简单?但是通常$exec会有问题,因为可能您的SQL语句会很长,您会遗漏.连接符,或者’来包围字符型字段。我 们可以注释mysql_query($exec);语句用echo $exec;代替来输出$exec以检查正确性。如果您还不能察觉$exec有什么错误的话,可以复制这个sql语句到phpmyadmin中执行,看看它的出错信息。还有需要注意的是,我们不要使用一些敏感的字符串作为字段名字,否则很可能会出现问题,比如说date什么的。变量的命名,字段的命名遵循一点规律有的时候对自己是一种好处,初学者并不可忽视其重要性。SESSION的使用SESSION的作用很多,最多用的就是站点内页面间变量传递。在页面开始我们要session_start();开启SESSION;然后就可以使用SESSION变量了,比如说要赋值就是:$_SESSION['item']=”item1″;要得到值就是$item1=$_SESSION['item'];,很简单吧。这里我们可能会使用到一些函数,比如说判断是不是某SESSION变量为空,可以这么写:empty($_SESSION['inum'])返回true or false。下面综合一下前面所说的我们来看一个登陆程序,判断用户名密码是否正确。登陆表单是这样:login.php Administrators Login Username Password 处理文件是这样<?require_once(’conn.php’);session_start();$username=$_POST['username'];$password=$_POST['password'];$exec=”select * from admin where username=’”.$username.”‘”;if($result=mysql_query($exec)){if($rs=mysql_fetch_object($result)){if($rs->password==$password){$_SESSION['adminname']=$username;header(”location:index.php”);}else{echo “alert(’Password Check Error!’);location.href=’login.php’;”;}}else{echo “alert(’Username Check Error!’);location.href=’login.php’;”;}}else{echo “alert(’Database Connection Error!’);location.href=’login.php’;”;}?>conn.php是这样:<?$conn=mysql_connect (”127.0.0.1″, “”, “”);mysql_select_db(”shop”);?>由于 $_SESSION['adminname']=$username;我们可以这样写验证是否登陆语句的文件:checkadmin.asp<?session_start();if($_SESSION['adminname']==”){echo “alert(’Please Login First’);location.href=’login.php’;”;}?>做一个分页显示关键就是用到了SQL语句中的limit来限定显示的记录从几到几。我们需要一个记录当前页的变量$page,还需要总共的记录数$num对于$page如果没有我们就让它=0,如果有<0就让它也=0,如果超过了总的页数就让他=总的页数。$execc=”select count(*) from tablename “;$resultc=mysql_query($execc);$rsc=mysql_fetch_array($resultc);$num=$rsc[0];这样可以得到记录总数ceil($num/10))如果一页10记录的话,这个就是总的页数所以可以这么写if(empty($_GET['page'])){$page=0;}else{$page=$_GET['page'];if($page<0)$page=0;if($page>=ceil($num/10))$page=ceil($num/10)-1;//因为page是从0开始的,所以要-1}这样$exec可以这么写 $exec=”select from tablename limit “.($page10).”,10″;//一页是10记录的最后我们需要做的就是几个连接:FirstPage”>NextPage
2023年08月04日
15 阅读
0 评论
0 点赞
2023-08-04
重构代码的技术
重构代码的技术
2023年08月04日
31 阅读
0 评论
0 点赞
2023-08-04
使用 PHP 管理 cron 作业
使用 PHP 管理 cron 作业crontab 或 cron 表是一个 Linux 系统进程/守护进程,有助于调度重复性任务,从而简化我们的日常工作。在本教程中,我们将创建一个动态 PHP 类,它允许我们使用安全连接来操作 crontab。背景:Crontab概述能够安排任务在后台运行真是太棒了!备份 SQL 数据库、获取或发送电子邮件、运行清理任务、分析性能,甚至获取 RSS 源 - cron 作业非常棒!尽管计划新作业的语法乍一看似乎令人生畏,但一旦分解它,就相对容易理解。cron 作业将始终有五列,每列代表一个按时间顺序排列的运算符,后跟要执行的完整路径和命令:home/path/to/command/the_command.sh按时间顺序排列的每个列都与任务计划具有特定的相关性。它们如下:分钟表示给定小时的分钟数,分别为 0-59。小时表示给定一天的小时数,分别为 0-23。天表示给定月份的天数,分别为 1-31。月表示给定年份的月份,分别为 1-12。星期几表示星期几,星期日到星期六,分别在数字上为 0-6。Minutes [0-59]| Hours [0-23]| | Days [1-31]| | | Months [1-12]| | | | Days of the Week [Numeric, 0-6]| | | | |home/path/to/command/the_command.sh因此,例如,如果您想将任务安排在每个月的第一天凌晨 12 点,它看起来像这样:0 0 1 home/path/to/command/the_command.sh另一方面,如果你想安排一个任务在每个星期六上午 8:30 运行,我们会这样写:30 8 6 home/path/to/command/the_command.sh还有许多运算符可用于进一步自定义时间表:逗号用于为任何 cron 列创建逗号分隔的值列表。短划线用于指定值范围。星号用于指定所有或每个值。默认情况下,crontab 会在执行计划任务时发送电子邮件通知。但是,在许多情况下,这是不需要的。我们可以通过将此命令的标准输出重定向到黑洞或设备来轻松抑制此功能。从本质上讲,这是一个文件,它将丢弃写入其中的所有内容。输出重定向通过运算符完成。让我们来看看如何使用我们的示例 cron 作业将标准输出重定向到黑洞,该作业在每个星期六上午 8:30 运行一个计划任务:/dev/null>30 8 6 home/path/to/command/the_command.sh >/dev/null此外,如果我们将标准输出重定向到 null 设备,我们可能还希望重定向标准错误。我们可以通过简单地将标准错误重定向到标准输出已经重定向到已经重定向的位置(空设备)来做到这一点!30 8 6 home/path/to/command/the_command.sh >/dev/null 2>&1使用 PHP 管理 crontab:蓝图为了使用 PHP 管理 crontab,我们需要能够以我们正在编辑其 crontab 的用户的身份在远程服务器上执行命令。虽然您可以使用 PHP 提供的 SSH2 库,但我们将使用 phpseclib 库,它支持不同的协议与远程服务器进行通信。如何安装和使用 phpseclib 库phpseclib库(PHP Secure Communications Library)是一个PHP库,它为SSH,SFTP和SSL / TLS等安全通信协议提供了一组方法和类。它使我们能够将安全通信功能整合到我们的应用程序中,而无需依赖外部命令行工具或扩展。如果你想知道为什么你更喜欢使用 phpseclib 而不是 PHP 提供的核心 SSH2 函数,让我们来看看 phpseclib 库的好处:SSH2 库提供的功能有限,可能不支持所有 SSH 功能提供抽象,使您可以轻松地在不同协议之间切换抽象底层协议的复杂性易于使用且直观它不需要任何外部依赖项或扩展支持多种安全通信协议,包括 SSH、SFTP、SCP、FTPS、SSL/TLS 等有据可查、积极开发和社区支持如您所见,phpseclib 库可以为安全通信需求提供更全面、更强大的解决方案。让我们看看如何安装它。您可以使用 composer 安装 phpseclib 库,如以下代码片段所示。$composer install phpseclib/phpseclib安装后,您可以通过在 PHP 脚本顶部包含自动加载器脚本来开始在 PHP 代码中使用 phpseclib 库,如以下代码片段所示。<?phprequire 'vendor/autoload.php';让我们快速浏览一下如何进行远程SSH2登录。<?phprequire 'vendor/autoload.php';use phpseclib3\Net\SSH2;$ssh = new SSH2('example.remote-server.com');if (!$ssh->login('ssh-username', 'ssh-password')) {die('Login to remote server failed.');}以上是对 phpseclib 库的简要介绍。类模板Ssh2_crontab_manager在本节中,我们将讨论需要在类中实现哪些方法。我们的类必须能够以适当的用户身份进行连接和身份验证,以便执行命令并访问用户的 crontab。因此,我们将建立一个 SSH2 连接并在构造函数本身中对其进行身份验证。有了经过身份验证的连接,我们需要一种方法来处理我们将运行的各种命令的执行。我们将使用 phpseclib 库提供的方法。通常,当我们需要在远程服务器上执行命令时,我们将从类的其他方法中调用此方法。exec()接下来,我们需要能够将 crontab 写入文件,以便我们可以切实地访问它。我们还需要一种方法在完成此文件后将其删除。我们将定义将 crontab 输出到文件的方法定义为 ,并将删除此文件的方法定义为 。write_to_file()remove_file()当然,我们还需要一种方法来创建和删除 cron 作业。因此,我们将分别定义和方法。append_cronjob()remove_cronjob()如果我们删除了唯一或最后一个 cron 作业,我们应该可以选择删除整个 crontab,而不是尝试创建一个空的 crontab。为了处理这种情况,我们可以使用该方法。remove_crontab()最后,我们将为类创建两个帮助程序方法。这些方法中的第一个将返回一个布尔值,它将简单地检查临时 cron 文件是否存在。后者将用于在发生错误时显示错误消息。我们将分别命名这些方法。crontab_file_exists()error_message()我们的准系统PHP类应该看起来像这样:<?phpuse phpseclib3\Net\SSH2;Class Ssh2_crontab_manager {private $connection; private $path; private $handle; private $cron_file; public function __construct() {...} public function exec() {...} public function write_to_file() {...} public function remove_file() {...} public function append_cronjob() {...} public function remove_cronjob() {...} public function remove_crontab() {...} private function crontab_file_exists() {...} private function error_message() {...}}?>实现类Ssh2_crontab_manager在本节中,我们将实现类的各种方法。构造函数类构造函数将主要负责建立和验证 SSH2 连接。让我们看一下方法。__constructpublic function __construct($host = null, $port = null, $username = null, $password = null){$path_length = strrpos(__FILE__, "/"); $this->path = substr(__FILE__, 0, $path_length) . '/'; $this->handle = 'crontab.txt'; $this->cron_file = "{$this->path}{$this->handle}"; try { if (is_null($host) || is_null($port) || is_null($username) || is_null($password)) { throw new Exception("Please specify the host, port, username, and password!"); } $this->connection = new SSH2($host, $port); if (!$this->connection->login($username, $password)) { throw new Exception("Could not authenticate '{$username}' using password: '{$password}'."); } } catch (Exception $e) { $this->error_message($e->getMessage()); }}首先,它需要四个参数,每个参数的默认值为:NULL$host:表示我们要连接的远程服务器的 IP 地址。$port:用于 SSH2 连接的端口。$username:表示服务器的用户的登录名。$password:表示用户对服务器的密码。首先,它计算当前文件的路径并将其设置为变量。它还设置要使用的 cron 文件的名称,并在 中构造 cron 文件的完整路径。$this->path$this->handle$this->cron_file然后,我们检查是否缺少任何必需的参数,如果是,它会抛出带有相应错误消息的异常。接下来,它通过传入 and 值来创建类的实例以建立 SSH 连接。SSH2$host$port最后,它尝试使用提供的 和 通过调用 SSH2 连接对象的方法进行身份验证。如果身份验证成功,则建立连接。如果失败,将引发异常。$username$passwordlogin()方法exec该方法负责在远程服务器上执行命令。这相当于手动将命令输入到像PuTTY这样的shell中。为了提供更大的灵活性,我们将公开此方法,以便用户可以实际执行他们可能需要运行的任何其他命令。exec让我们看一下方法。execpublic function exec(){$argument_count = func_num_args(); try { if (!$argument_count) { throw new Exception("There is nothing to execute, no arguments specified."); } $arguments = func_get_args(); $command_string = ($argument_count > 1) ? implode(" && ", $arguments) : $arguments[0]; $stream = $this->connection->exec($command_string); if (!$stream) { throw new Exception("Unable to execute the specified commands: <br />{$command_string}"); } } catch (Exception $e) { $this->error_message($e->getMessage()); } return $this;}我们的方法使用 phpseclib 库的方法执行命令。exec()exec在此方法中,我们要做的第一件事是定义一个变量,表示传递的参数总数的计数。我们将使用 PHP 的函数来获取此计数。接下来,在 try 块中,我们将检查是否将任何参数传递给此方法。如果参数计数为 0,我们将抛出带有相应消息的新异常。func_num_args()接下来,使用该函数,我们将创建一个包含传递给此方法的所有参数的数组。然后,使用三元运算符,我们将定义一个新变量 ,作为我们将要执行的实际 Linux 命令的单行字符串表示形式。func_get_args()$command_string如果我们确实有多个命令要执行,我们将使用 PHP 的函数将参数数组解析为字符串。我们将两个参数传递给:胶水或分隔符,它基本上只是一个将插入数组元素之间的字符串,以及数组本身。我们将使用 Linux 运算符分隔每个元素,这允许我们在一行上按顺序执行多个命令!implode()implode()&&准备好命令并将其解析为字符串后,我们现在可以尝试使用 SSH2 类中的方法通过已建立的 SSH 连接执行命令字符串。返回值存储在变量中。exec()$stream方法write_to_file下一个方法 , 将负责将现有 crontab 写入临时文件,或者在不存在 cron 作业时创建一个空白的临时文件。这将需要两个参数:write_to_file()我们将创建的临时文件的路径创建时应该使用的名称该方法应如下所示。write_to_filepublic function write_to_file($path=NULL, $handle=NULL){if (! $this->crontab_file_exists()) { $this->handle = (is_null($handle)) ? $this->handle : $handle; $this->path = (is_null($path)) ? $this->path : $path; $this->cron_file = "{$this->path}{$this->handle}"; $init_cron = "crontab -l > {$this->cron_file} && [ -f {$this->cron_file} ] || > {$this->cron_file}"; $this->exec($init_cron); } return $this;}首先,我们使用布尔方法检查 cron 文件是否已存在,我们稍后将创建该方法。如果文件存在,则无需继续。如果没有,我们将使用三元运算符来检查 和 props 以确定它们是否是 .如果它们中的任何一个是 ,我们将使用构造函数中的预定义回退来定义它们。crontab_file_exists()$path$handleNULLNULL然后,我们将这些属性连接成一个新属性,该属性表示临时 cron 文件的完整路径和文件名。接下来,我们使用带有参数的 Linux 命令将用户 crontab 显示为标准输出。然后,使用 Linux 的运算符,我们将标准输出或我们的临时 cron 文件重定向到我们的临时 cron 文件,方法是连接到命令字符串!使用运算符将输出重定向到文件将始终创建该文件(如果该文件不存在)。crontab-l>STDOUT$this->cron_file>这很好用,但前提是 crontab 中已经安排了作业。如果没有 cron 作业,则永远不会创建此文件!但是,使用运算符,我们可以将其他命令/表达式附加到此字符串中。因此,让我们附加一个条件表达式来检查 cron 文件是否存在。如果该文件不存在,则此表达式的计算结果将为 false。因此,如果需要,我们可以在此条件之后使用 or 运算符创建一个新的空白文件。&&||or如果条件计算结果为 false,则在之后放置的命令将执行。现在,通过再次使用运算符,这次没有在它前面加上特定的命令,我们可以创建一个新的空白文件。因此,从本质上讲,这串命令会将 crontab 输出到一个文件中,然后检查该文件是否存在,这将指示 crontab 中有条目,然后创建一个新的空白文件(如果它尚不存在)。or>最后,我们调用了该方法并将命令字符串作为唯一的参数传递给它。然后,为了使此方法也可链接,我们将返回 .exec()$this方法remove_file让我们快速看一下该方法。remove_filepublic function remove_file(){if ($this->crontab_file_exists()) $this->exec("rm {$this->cron_file}"); return $this;}在此方法中,我们使用辅助方法 , 来检查临时 cron 文件是否存在,然后执行 Linux 命令将其删除(如果存在)。像往常一样,我们还将返回以保持链条可伸缩性。crontab_file_exists()rm$this方法append_cronjob该方法通过将新的作业/行添加到临时 cron 文件,然后在该文件上执行命令来创建新的 cron 作业,这会将所有这些作业安装为新的 crontab。append_cronjobcrontab它看起来像这样:public function append_cronjob($cron_jobs=NULL){if (is_null($cron_jobs)) $this->error_message("Nothing to append! Please specify a cron job or an array of cron jobs."); $append_cronfile = "echo '"; $append_cronfile .= (is_array($cron_jobs)) ? implode("\n", $cron_jobs) : $cron_jobs; $append_cronfile .= "' >> {$this->cron_file}"; $install_cron = "crontab {$this->cron_file}"; $this->write_to_file()->exec($append_cronfile, $install_cron)->remove_file(); return $this;}该方法接受一个参数,该参数将是一个字符串或表示要追加的 cron 作业的字符串数组。append_cronjob()$cron_jobs我们将通过确定参数是否为 .如果是,我们将调用该方法以停止任何进一步的执行,并向用户显示错误消息。$cron_jobsNULLerror_message()接下来,我们将一个新变量 定义为字符串,文本后跟空格,末尾带有单引号。我们将暂时用我们正在添加的各种 cron 作业以及结束引号填充此字符串。我们将使用字符串连接运算符构建此字符串。$append_cronfileecho.=接下来,使用三元运算符,我们确定是否是数组。如果是,我们将用换行符内爆该数组,以便每个 cron 作业都写在 cron 文件中自己的行上。如果参数不是数组,我们将简单地将该作业连接到字符串上,而无需任何特殊处理。$cron_jobs\n$cron_jobs$append_cron本质上,我们可以通过再次将标准输出重定向到文件中来将我们的任务回显到 cron 文件中。因此,通过使用字符串连接运算符,我们将右单引号附加到命令字符串,以及 Linux 运算符,后跟 cron 文件的完整路径和文件名。与始终覆盖文件的运算符不同,运算符将输出追加到文件末尾。因此,通过使用此运算符,我们不会覆盖任何现有的 cron 作业。>>>>>接下来,我们将一个变量定义为字符串,使用我们将用于安装我们将要创建的新 cron 文件的命令。这就像调用 crontab 命令一样简单,后跟 cron 文件的路径和文件名。最后,在通过该方法执行这些命令之前,我们将首先调用该方法来创建临时 cron 文件。然后,在链中,我们将执行这些命令并调用该方法删除临时文件。最后,我们将返回,以便该方法可链接。exec()write_to_file()remove_file()$thisappend_cronjob()方法remove_cronjob现在我们可以创建新的 cron 作业,我们也有能力删除它们是合乎逻辑的!这就是该方法的目的。remove_cronjob一起来看看吧。public function remove_cronjob($cron_jobs=NULL){if (is_null($cron_jobs)) $this->error_message("Nothing to remove! Please specify a cron job or an array of cron jobs."); $this->write_to_file(); $cron_array = file($this->cron_file, FILE_IGNORE_NEW_LINES); if (empty($cron_array)) $this->error_message("Nothing to remove! The cronTab is already empty."); $original_count = count($cron_array); if (is_array($cron_jobs)) { foreach ($cron_jobs as $cron_regex) $cron_array = preg_grep($cron_regex, $cron_array, PREG_GREP_INVERT); } else { $cron_array = preg_grep($cron_jobs, $cron_array, PREG_GREP_INVERT); } return ($original_count === count($cron_array)) ? $this->remove_file() : $this->remove_crontab()->append_cronjob($cron_array);}它需要一个参数,这将是一个(简单的)正则表达式。它将用于在 crontab 中查找匹配的作业并相应地删除它们。创建 cron 文件后,我们现在将使用 PHP 的函数将其读入数组。此函数会将给定文件解析为数组,每行都作为数组元素。我们将 cron 文件作为第一个参数传递给此函数,然后设置一个特殊标志,这将强制忽略所有新行。因此,我们有一个只有 cron 作业本身的数组。如果没有计划任何 cron 作业,则此数组将为空。随后,将没有理由继续。因此,我们已经检查了 是否为空,如果是,则停止执行。file()FILE_IGNORE_NEW_LINESfile()$cron_array现在,我们确定参数是否是数组。如果它是一个数组,我们用循环遍历它。在该循环中,我们执行一个 函数 .这个漂亮的函数,与 不同,将返回与指定的正则表达式匹配的所有数组元素的数组。但是,在这种情况下,我们需要不匹配的数组元素。换句话说,我们需要一个包含我们将要保留的所有 cron 作业的数组,以便我们可以只使用这些作业初始化 crontab。因此,我们将在这里设置一个特殊的标志,这将导致返回一个与正则表达式不匹配的所有元素的数组。因此,我们将拥有一系列我们想要保留的所有 cron 作业。$cron_jobsforeachpreg_grep()preg_match()PREG_GREP_INVERTpreg_grep()如果参数不是数组,我们将以相同的方式进行,但没有任何迭代。同样,我们将重新定义为设置了标志的函数的结果数组。$cron_jobs$cron_arraypreg_grep()PREG_GREP_INVERT使用我们的集合,现在我们将该数组的当前长度与其原始长度进行比较,我们将其缓存在变量中。如果长度相同,我们将简单地返回删除临时 cron 文件的方法。如果它们不匹配,我们将删除现有的 crontab,然后安装新的。$cron_array$original_countremove_file()方法remove_crontab删除整个 crontab 相对容易实现,如以下代码片段所示。public function remove_crontab(){$this->exec("crontab -r")->remove_file(); return $this;}其他帮助程序方法在编写了首当其冲的 cron 管理类之后,我们现在将看看我们在整个课程中使用的两个小而有用的方法,以及 .crontab_file_exists()error_message()crontab_file_exists法此方法返回 PHP 方法的结果,或者 ,具体取决于临时 cron 文件是否存在。file_exists()truefalseprivate function crontab_file_exists(){return file_exists($this->cron_file);}error_message法此方法采用单个参数(一个字符串)表示我们要显示的错误消息。然后,我们将调用 PHP 的方法停止执行并显示此消息。字符串本身将连接成一个应用简单样式的元素。die()private function error_message($error){die("<pre style='color:#EE2711'>ERROR: {$error}</pre>");}完整的类如下所示:<?phpuse phpseclib3\Net\SSH2;Class Ssh2_crontab_manager {private $connection; private $path; private $handle; private $cron_file; public function __construct($host = null, $port = null, $username = null, $password = null) { $path_length = strrpos(__FILE__, "/"); $this->path = substr(__FILE__, 0, $path_length) . '/'; $this->handle = 'crontab.txt'; $this->cron_file = "{$this->path}{$this->handle}"; try { if (is_null($host) || is_null($port) || is_null($username) || is_null($password)) { throw new Exception("Please specify the host, port, username, and password!"); } $this->connection = new SSH2($host, $port); if (!$this->connection->login($username, $password)) { throw new Exception("Could not authenticate '{$username}' using password: '{$password}'."); } } catch (Exception $e) { $this->error_message($e->getMessage()); } } public function exec() { $argument_count = func_num_args(); try { if (!$argument_count) { throw new Exception("There is nothing to execute, no arguments specified."); } $arguments = func_get_args(); $command_string = ($argument_count > 1) ? implode(" && ", $arguments) : $arguments[0]; $stream = $this->connection->exec($command_string); if (!$stream) { throw new Exception("Unable to execute the specified commands: <br />{$command_string}"); } } catch (Exception $e) { $this->error_message($e->getMessage()); } return $this; } public function write_to_file($path=NULL, $handle=NULL) { if (! $this->crontab_file_exists()) { $this->handle = (is_null($handle)) ? $this->handle : $handle; $this->path = (is_null($path)) ? $this->path : $path; $this->cron_file = "{$this->path}{$this->handle}"; $init_cron = "crontab -l > {$this->cron_file} && [ -f {$this->cron_file} ] || > {$this->cron_file}"; $this->exec($init_cron); } return $this; } public function remove_file() { if ($this->crontab_file_exists()) $this->exec("rm {$this->cron_file}"); return $this; } public function append_cronjob($cron_jobs=NULL) { if (is_null($cron_jobs)) $this->error_message("Nothing to append! Please specify a cron job or an array of cron jobs."); $append_cronfile = "echo '"; $append_cronfile .= (is_array($cron_jobs)) ? implode("\n", $cron_jobs) : $cron_jobs; $append_cronfile .= "' >> {$this->cron_file}"; $install_cron = "crontab {$this->cron_file}"; $this->write_to_file()->exec($append_cronfile, $install_cron)->remove_file(); return $this; } public function remove_cronjob($cron_jobs=NULL) { if (is_null($cron_jobs)) $this->error_message("Nothing to remove! Please specify a cron job or an array of cron jobs."); $this->write_to_file(); $cron_array = file($this->cron_file, FILE_IGNORE_NEW_LINES); if (empty($cron_array)) $this->error_message("Nothing to remove! The cronTab is already empty."); $original_count = count($cron_array); if (is_array($cron_jobs)) { foreach ($cron_jobs as $cron_regex) $cron_array = preg_grep($cron_regex, $cron_array, PREG_GREP_INVERT); } else { $cron_array = preg_grep($cron_jobs, $cron_array, PREG_GREP_INVERT); } return ($original_count === count($cron_array)) ? $this->remove_file() : $this->remove_crontab()->append_cronjob($cron_array); } public function remove_crontab() { $this->exec("crontab -r")->remove_file(); return $this; } private function crontab_file_exists() { return file_exists($this->cron_file); } private function error_message($error) { die("<pre style='color:#EE2711'>ERROR: {$error}</pre>"); }}?>Putting It All TogetherNow that we've completed our cron management class, let's take a look at a few examples of how to use it.Instantiating the Class and Establishing an Authenticated ConnectionFirstly, let's create a new instance of our class. Remember, we'll need to pass the IP address, port, username, and password to the class constructor.<?phprequire 'vendor/autoload.php';include "./ssh2_crontab_manager.php";$crontab = new Ssh2_crontab_manager('11.11.111.111', '22', 'my_username', 'my_password');Appending a Single Cron JobWith an authenticated connection in place, let's have a look at how we can create a new, single, cron job.<?phprequire 'vendor/autoload.php';include "./ssh2_crontab_manager.php";$crontab = new Ssh2_crontab_manager('11.11.111.111', '22', 'my_username', 'my_password');$crontab->append_cronjob('30 8 6 home/path/to/command/the_command.sh >/dev/null 2>&1');Appending an Array of Cron JobsAppending multiple cron jobs is just as easy as appending a single cron job. We'll simply pass an array to the method.append_cronjob()<?phprequire 'vendor/autoload.php';include "./ssh2_crontab_manager.php";$crontab = new Ssh2_crontab_manager('11.11.111.111', '22', 'my_username', 'my_password');$new_cronjobs = array('0 0 1 * * home/path/to/command/the_command.sh', '30 8 * * 6 home/path/to/command/the_command.sh >/dev/null 2>&1');$crontab->append_cronjob($new_cronjobs);Removing a Single Cron Job与创建单个 cron 作业的方式类似,我们现在将删除一个。但是,这一次,我们将使用正则表达式来查找适当的任务。此正则表达式可以像您需要的那样简单或复杂。实际上,有许多方法可以为您正在寻找的任务进行正则表达式。例如,如果您需要删除的任务是唯一的,因为正在运行的命令未在 crontab 中的其他任何地方使用,则只需将命令名称指定为正则表达式即可。此外,如果要删除某个月的所有任务,只需编写一个正则表达式即可查找给定月份所有作业的匹配项。<?phprequire 'vendor/autoload.php';include "./ssh2_crontab_manager.php";$crontab = new Ssh2_crontab_manager('11.11.111.111', '22', 'my_username', 'my_password');$cron_regex = '/home/path/to/command/the_command.sh/';$crontab->remove_cronjob($cron_regex);删除 cron 作业数组删除多个 cronjob 的处理方式与删除单个 cronjob 的方式相同,但有一个例外:我们将一个 cron job 正则表达式数组传递给该方法。remove_cronjob()<?phprequire 'vendor/autoload.php';include "./ssh2_crontab_manager.php";$crontab = new Ssh2_crontab_manager('11.11.111.111', '22', 'my_username', 'my_password');$cron_regex = array('/0 0 1 \* \*/', '/home\/path\/to\/command\/the_command\.sh\/');$crontab->remove_cronjob($cron_regex);
2023年08月04日
18 阅读
0 评论
0 点赞
2023-08-04
基于PHP的cURL快速入门
基于PHP的cURL快速入门cURL 是一个利用URL语法规定来传输文件和数据的工具,支持很多协议,如HTTP、FTP、TELNET等。最爽的是,PHP也支持 cURL 库。本文将介绍 cURL 的一些高级特性,以及在PHP中如何运用它。为什么要用 cURL?是的,我们可以通过其他办法获取网页内容。大多数时候,我因为想偷懒,都直接用简单的PHP函数:以下为引用的内容:$content = file_get_contents("http://www.nettuts.com");// or$lines = file("http://www.nettuts.com");// orreadfile(http://www.nettuts.com);不过,这种做法缺乏灵活性和有效的错误处理。而且,你也不能用它完成一些高难度任务——比如处理coockies、验证、表单提交、文件上传等等。引用:cURL 是一种功能强大的库,支持很多不同的协议、选项,能提供 URL 请求相关的各种细节信息。基本结构在学习更为复杂的功能之前,先来看一下在PHP中建立cURL请求的基本步骤:初始化设置变量执行并获取结果释放cURL句柄以下为引用的内容:// 1. 初始化$ch = curl_init();// 2. 设置选项,包括URLcurl_setopt($ch, CURLOPT_URL, "http://www.nettuts.com");curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch, CURLOPT_HEADER, 0);// 3. 执行并获取HTML文档内容$output = curl_exec($ch);// 4. 释放curl句柄curl_close($ch);第二步(也就是 curl_setopt() )最为重要,一切玄妙均在此。有一长串cURL参数可供设置,它们能指定URL请求的各个细节。要一次性全部看完并理解可能比较困难,所以今天我们只试一下那些更常用也更有用的选项。检查错误你可以加一段检查错误的语句(虽然这并不是必需的):以下为引用的内容:// ...$output = curl_exec($ch);if ($output === FALSE) {echo "cURL Error: " . curl_error($ch);}// ...请注意,比较的时候我们用的是“=== FALSE”,而非“== FALSE”。因为我们得区分 空输出 和 布尔值FALSE,后者才是真正的错误.获取信息这是另一个可选的设置项,能够在cURL执行后获取这一请求的有关信息:以下为引用的内容:// ...curl_exec($ch);$info = curl_getinfo($ch);echo '获取'. $info['url'] . '耗时'. $info['total_time'] . '秒';// ...返回的数组中包括了以下信息:“url” //资源网络地址“content_type” //内容编码“http_code” //HTTP状态码“header_size” //header的大小“request_size” //请求的大小“filetime” //文件创建时间“ssl_verify_result” //SSL验证结果“redirect_count” //跳转技术“total_time” //总耗时“namelookup_time” //DNS查询耗时“connect_time” //等待连接耗时“pretransfer_time” //传输前准备耗时“size_upload” //上传数据的大小“size_download” //下载数据的大小“speed_download” //下载速度“speed_upload” //上传速度“download_content_length”//下载内容的长度“upload_content_length” //上传内容的长度“starttransfer_time” //开始传输的时间“redirect_time”//重定向耗时基于浏览器的重定向在第一个例子中,我们将提供一段用于侦测服务器是否有基于浏览器的重定向的代码。例如,有些网站会根据是否是手机浏览器甚至用户来自哪个国家来重定向网页。我们利用 CURLOPT_HTTPHEADER 选项来设定我们发送出的HTTP请求头信息(http headers),包括user agent信息和默认语言。然后我们来看看这些特定网站是否会把我们重定向到不同的URL。以下为引用的内容:// 测试用的URL$urls = array("http://www.cnn.com","http://www.mozilla.com","http://www.facebook.com");// 测试用的浏览器信息$browsers = array("standard" => array ("user_agent" => "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)","language" => "en-us,en;q=0.5"),"iphone" => array ("user_agent" => "Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A537a Safari/419.3","language" => "en"),"french" => array ("user_agent" => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)","language" => "fr,fr-FR;q=0.5"));foreach ($urls as $url) {echo "URL: $url\n";foreach ($browsers as $test_name => $browser) {$ch = curl_init();// 设置 urlcurl_setopt($ch, CURLOPT_URL, $url);// 设置浏览器的特定headercurl_setopt($ch, CURLOPT_HTTPHEADER, array("User-Agent: {$browser['user_agent']}","Accept-Language: {$browser['language']}"));// 页面内容我们并不需要curl_setopt($ch, CURLOPT_NOBODY, 1);// 只需返回HTTP headercurl_setopt($ch, CURLOPT_HEADER, 1);// 返回结果,而不是输出它curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);$output = curl_exec($ch);curl_close($ch);// 有重定向的HTTP头信息吗?if (preg_match("!Location: (.*)!", $output, $matches)) {echo "$test_name: redirects to $matches[1]\n";} else {echo "$test_name: no redirection\n";}}echo "\n\n";}首先,我们建立一组需要测试的URL,接着指定一组需要测试的浏览器信息。最后通过循环测试各种URL和浏览器匹配可能产生的情况。因为我们指定了cURL选项,所以返回的输出内容则只包括HTTP头信息(被存放于 $output 中)。利用一个简单的正则,我们检查这个头信息中是否包含了“Location:”字样。运行这段代码应该会返回如下结果:URL: http://www.cnn.comstandard: no redirectioniphone: redirects to http://m.cnn.comfrench: no redirectionURL: http://www.mozilla.comstandard: redirects to http://www.mozilla.com/en-US/iphone: redirects to http://www.mozilla.com/en-US/french: redirects to http://www.mozilla.com/fr/URL: http://www.facebook.comstandard: no redirectioniphone: redirects to http://touch.facebook.com/?w2mfrench: no redirection用POST方法发送数据当发起GET请求时,数据可以通过“查询字串”(query string)传递给一个URL。例如,在google中搜索时,搜索关键即为URL的查询字串的一部分:http://www.google.com/search?q=nettuts这种情况下你可能并不需要cURL来模拟。把这个URL丢给“file_get_contents()”就能得到相同结果。不过有一些HTML表单是用POST方法提交的。这种表单提交时,数据是通过 HTTP请求体(request body) 发送,而不是查询字串。例如,当使用CodeIgniter论坛的表单,无论你输入什么关键字,总是被POST到如下页面:http://codeigniter.com/forums/do_search/你可以用PHP脚本来模拟这种URL请求。首先,新建一个可以接受并显示POST数据的文件,我们给它命名为post_output.php:print_r($_POST);接下来,写一段PHP脚本来执行cURL请求:以下为引用的内容:$url = "http://localhost/post_output.php";$post_data = array ("foo" => "bar","query" => "Nettuts","action" => "Submit");$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);// 我们在POST数据哦!curl_setopt($ch, CURLOPT_POST, 1);// 把post的变量加上curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);$output = curl_exec($ch);curl_close($ch);echo $output;执行代码后应该会得到以下结果:Array([foo]=>bar[query]=>Nettuts[action]=>Submit)这段脚本发送一个POST请求给 post_output.php ,这个页面 $_POST 变量并返回,我们利用cURL捕捉了这个输出。文件上传上传文件和前面的POST十分相似。因为所有的文件上传表单都是通过POST方法提交的。首先新建一个接收文件的页面,命名为 upload_output.php:print_r($_FILES);以下是真正执行文件上传任务的脚本:以下为引用的内容:$url = "http://localhost/upload_output.php";$post_data = array ("foo" => "bar",// 要上传的本地文件地址"upload" => "@C:/wamp/www/test.zip");$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch, CURLOPT_POST, 1);curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);$output = curl_exec($ch);curl_close($ch);echo $output;如果你需要上传一个文件,只需要把文件路径像一个post变量一样传过去,不过记得在前面加上@符号。执行这段脚本应该会得到如下输出:Array([upload]=>Array([name]=>test.zip[type]=>application/octet-stream[tmp_name]=>C:\wamp\tmp\php4CCB.tmp[error]=>0[size]=>1183642))cURL批处理(multi cURL)cURL还有一个高级特性——批处理句柄(handle)。这一特性允许你同时或异步地打开多个URL连接。下面是来自来自php.net的示例代码:以下为引用的内容:// 创建两个cURL资源$ch1 = curl_init();$ch2 = curl_init();// 指定URL和适当的参数curl_setopt($ch1, CURLOPT_URL, "http://lxr.php.net/");curl_setopt($ch1, CURLOPT_HEADER, 0);curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/");curl_setopt($ch2, CURLOPT_HEADER, 0);// 创建cURL批处理句柄$mh = curl_multi_init();// 加上前面两个资源句柄curl_multi_add_handle($mh,$ch1);curl_multi_add_handle($mh,$ch2);// 预定义一个状态变量$active = null;// 执行批处理do {$mrc = curl_multi_exec($mh, $active);} while ($mrc == CURLM_CALL_MULTI_PERFORM);while ($active && $mrc == CURLM_OK) {if (curl_multi_select($mh) != -1) {do {$mrc = curl_multi_exec($mh, $active);} while ($mrc == CURLM_CALL_MULTI_PERFORM);}}// 关闭各个句柄curl_multi_remove_handle($mh, $ch1);curl_multi_remove_handle($mh, $ch2);curl_multi_close($mh);这里要做的就是打开多个cURL句柄并指派给一个批处理句柄。然后你就只需在一个while循环里等它执行完毕。这个示例中有两个主要循环。第一个 do-while 循环重复调用 curl_multi_exec() 。这个函数是无隔断(non-blocking)的,但会尽可能少地执行。它返回一个状态值,只要这个值等于常量 CURLM_CALL_MULTI_PERFORM ,就代表还有一些刻不容缓的工作要做(例如,把对应URL的http头信息发送出去)。也就是说,我们需要不断调用该函数,直到返回值发生改变。而接下来的 while 循环,只在 $active 变量为 true 时继续。这一变量之前作为第二个参数传给了 curl_multi_exec() ,代表只要批处理句柄中是否还有活动连接。接着,我们调用 curl_multi_select() ,在活动连接(例如接受服务器响应)出现之前,它都是被“屏蔽”的。这个函数成功执行后,我们又会进入另一个 do-while 循环,继续下一条URL。还是来看一看怎么把这一功能用到实处吧:WordPress 连接检查器想象一下你有一个文章数目庞大的博客,这些文章中包含了大量外部网站链接。一段时间之后,因为这样那样的原因,这些链接中相当数量都失效了。要么是被和谐了,要么是整个站点都被功夫网了...我们下面建立一个脚本,分析所有这些链接,找出打不开或者404的网站/网页,并生成一个报告。请注意,以下并不是一个真正可用的WordPress插件,仅仅是一段独立功能的脚本而已,仅供演示,谢谢。好,开始吧。首先,从数据库中读取所有这些链接:以下为引用的内容:// CONFIG$db_host = 'localhost';$db_user = 'root';$db_pass = '';$db_name = 'wordpress';$excluded_domains = array('localhost', 'www.mydomain.com');$max_connections = 10;// 初始化一些变量$url_list = array();$working_urls = array();$dead_urls = array();$not_found_urls = array();$active = null;// 连到 MySQLif (!mysql_connect($db_host, $db_user, $db_pass)) {die('Could not connect: ' . mysql_error());}if (!mysql_select_db($db_name)) {die('Could not select db: ' . mysql_error());}// 找出所有含有链接的文章$q = "SELECT post_content FROM wp_postsWHERE post_content LIKE '%href=%'AND post_status = 'publish'AND post_type = 'post'";$r = mysql_query($q) or die(mysql_error());while ($d = mysql_fetch_assoc($r)) {// 用正则匹配链接if (preg_match_all("!href=\"(.*?)\"!", $d['post_content'], $matches)) {foreach ($matches[1] as $url) {// exclude some domains$tmp = parse_url($url);if (in_array($tmp['host'], $excluded_domains)) {continue;}// store the url$url_list []= $url;}}}// 移除重复链接$url_list = array_values(array_unique($url_list));if (!$url_list) {die('No URL to check');}我们首先配置好数据库,一系列要排除的域名($excluded_domains),以及最大并发连接数($max_connections)。然后,连接数据库,获取文章和包含的链接,把它们收集到一个数组中($url_list)。下面的代码有点复杂了,因此我将一小步一小步地详细解释:以下为引用的内容:// 1. 批处理器$mh = curl_multi_init();// 2. 加入需批量处理的URLfor ($i = 0; $i < $max_connections; $i++) {add_url_to_multi_handle($mh, $url_list);}// 3. 初始处理do {$mrc = curl_multi_exec($mh, $active);} while ($mrc == CURLM_CALL_MULTI_PERFORM);// 4. 主循环while ($active && $mrc == CURLM_OK) {// 5. 有活动连接if (curl_multi_select($mh) != -1) {// 6. 干活do {$mrc = curl_multi_exec($mh, $active);} while ($mrc == CURLM_CALL_MULTI_PERFORM);// 7. 有信息否?if ($mhinfo = curl_multi_info_read($mh)) {// 意味着该连接正常结束// 8. 从curl句柄获取信息$chinfo = curl_getinfo($mhinfo['handle']);// 9. 死链么?if (!$chinfo['http_code']) {$dead_urls []= $chinfo['url'];// 10. 404了?} else if ($chinfo['http_code'] == 404) {$not_found_urls []= $chinfo['url'];// 11. 还能用} else {$working_urls []= $chinfo['url'];}// 12. 移除句柄curl_multi_remove_handle($mh, $mhinfo['handle']);curl_close($mhinfo['handle']);// 13. 加入新URL,干活if (add_url_to_multi_handle($mh, $url_list)) {do {$mrc = curl_multi_exec($mh, $active);} while ($mrc == CURLM_CALL_MULTI_PERFORM);}}}}// 14. 完了curl_multi_close($mh);echo "==Dead URLs==\n";echo implode("\n",$dead_urls) . "\n\n";echo "==404 URLs==\n";echo implode("\n",$not_found_urls) . "\n\n";echo "==Working URLs==\n";echo implode("\n",$working_urls);// 15. 向批处理器添加urlfunction add_url_to_multi_handle($mh, $url_list) {static $index = 0;// 如果还剩url没用if ($url_list[$index]) {// 新建curl句柄$ch = curl_init();// 配置urlcurl_setopt($ch, CURLOPT_URL, $url_list[$index]);// 不想输出返回的内容curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);// 重定向到哪儿我们就去哪儿curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// 不需要内容体,能够节约带宽和时间curl_setopt($ch, CURLOPT_NOBODY, 1);// 加入到批处理器中curl_multi_add_handle($mh, $ch);// 拨一下计数器,下次调用该函数就能添加下一个url了$index++;return true;} else {// 没有新的URL需要处理了return false;}}下面解释一下以上代码。列表的序号对应着代码注释中的顺序数字。新建一个批处理器。Created a multi handle.稍后我们将创建一个把URL加入批处理器的函数 add_url_to_multi_handle() 。每当这个函数被调用,就有一个新url被加入批处理器。一开始,我们给批处理器添加了10个URL(这一数字由 $max_connections 所决定)。 运行 curl_multi_exec() 进行初始化工作是必须的,只要它返回 CURLM_CALL_MULTI_PERFORM 就还有事情要做。这么做主要是为了创建连接,它不会等待完整的URL响应。只要批处理中还有活动连接主循环就会一直持续。curl_multi_select() 会一直等待,直到某个URL查询产生活动连接。cURL的活儿又来了,主要是获取响应数据。检查各种信息。当一个URL请求完成时,会返回一个数组。在返回的数组中有一个 cURL 句柄。我们利用其获取单个cURL请求的相应信息。如果这是一个死链或者请求超时,不会返回http状态码。如果这个页面找不到了,会返回404状态码。其他情况我们都认为这个链接是可用的(当然,你也可以再检查一下500错误之类...)。从该批次移除这个cURL句柄,因为它已经没有利用价值了,关了它!很好,现在可以另外加一个URL进来了。再一次地,初始化工作又开始进行...嗯,该干的都干了。关闭批处理器,生成报告。回过头来看给批处理器添加新URL的函数。这个函数每调用一次,静态变量 $index 就递增一次,这样我们才能知道还剩多少URL没处理。我把这个脚本在我的博客上跑了一遍(测试需要,有一些错误链接是故意加上的),结果如下:以下为引用的内容:共检查约40个URL,只耗费两秒不到。当需要检查更加大量的URL时,其省心省力的效果可想而知!如果你同时打开10个连接,还能再快上10倍!另外,你还可以利用cURL批处理的无隔断特性来处理大量URL请求,而不会阻塞你的Web脚本。另一些有用的cURL 选项HTTP 认证如果某个URL请求需要基于 HTTP 的身份验证,你可以使用下面的代码:复制内容到剪贴板代码:以下为引用的内容:$url = "http://www.somesite.com/members/";$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);// 发送用户名和密码curl_setopt($ch, CURLOPT_USERPWD, "myusername:mypassword");// 你可以允许其重定向curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// 下面的选项让 cURL 在重定向后// 也能发送用户名和密码curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH, 1);$output = curl_exec($ch);curl_close($ch);FTP 上传PHP 自带有 FTP 类库, 但你也能用 cURL:以下为引用的内容:// 开一个文件指针$file = fopen("/path/to/file", "r");// url里包含了大部分所需信息$url = "ftp://username:password@mydomain.com:21/path/to/new/file";$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);// 上传相关的选项curl_setopt($ch, CURLOPT_UPLOAD, 1);curl_setopt($ch, CURLOPT_INFILE, $fp);curl_setopt($ch, CURLOPT_INFILESIZE, filesize("/path/to/file"));// 是否开启ASCII模式 (上传文本文件时有用)curl_setopt($ch, CURLOPT_FTPASCII, 1);$output = curl_exec($ch);curl_close($ch);翻墙术你可以用代理发起cURL请求:以下为引用的内容:$ch = curl_init();curl_setopt($ch, CURLOPT_URL,'http://www.example.com');curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);// 指定代理地址curl_setopt($ch, CURLOPT_PROXY, '11.11.11.11:8080');// 如果需要的话,提供用户名和密码curl_setopt($ch, CURLOPT_PROXYUSERPWD,'user:pass');$output = curl_exec($ch);curl_close ($ch);回调函数可以在一个URL请求过程中,让cURL调用某指定的回调函数。例如,在内容或者响应下载的过程中立刻开始利用数据,而不用等到完全下载完。以下为引用的内容:$ch = curl_init();curl_setopt($ch, CURLOPT_URL,'http://net.tutsplus.com');curl_setopt($ch, CURLOPT_WRITEFUNCTION,"progress_function");curl_exec($ch);curl_close ($ch);function progress_function($ch,$str) {echo $str;return strlen($str);}这个回调函数必须返回字串的长度,不然此功能将无法正常使用。在URL响应接收的过程中,只要收到一个数据包,这个函数就会被调用。小结今天我们一起学习了cURL库的强大功能和灵活的扩展性。希望你喜欢。下一次要发起URL请求时,考虑下cURL吧!英文原文:http://net.tutsplus.com/tutorial%20...%20for-mastering-curl/原文作者:Burak Guzel本文链接:http://www.blueidea.com/tech/program/2010/7348.aspHow to Use cURL in PHP
2023年08月04日
11 阅读
0 评论
0 点赞
1
...
140
141
142
...
157