首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
182 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
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
累计撰写
786
篇文章
累计收到
30
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
138
篇与
的结果
2023-12-28
php与sku组合,用笛卡尔积实现!
php与sku组合,用笛卡尔积实现!可以使用笛卡尔积来实现 sku 的组合。假设有三个数组分别是颜色数组、尺寸数组和版本数组,可以先把它们组合成一个二维数组,然后再进行笛卡尔积操作,最终得到 sku 数组。示例代码如下:// 颜色数组 $colors = array('红色', '蓝色', '绿色'); // 尺寸数组 $sizes = array('S', 'M', 'L'); // 版本数组 $versions = array('V1', 'V2', 'V3'); // 组合数组 $combinations = array(); foreach ($colors as $color) { foreach ($sizes as $size) { foreach ($versions as $version) { $combinations[] = array('颜色' => $color, '尺寸' => $size, '版本' => $version); } } } // 笛卡尔积操作 function cartesianProduct($arr) { $result = array(); foreach ($arr as $key => $values) { if (empty($values)) { continue; } if (empty($result)) { foreach ($values as $value) { $result[] = array($key => $value); } } else { $append = array(); foreach ($result as &$product) { $product[$key] = array_shift($values); $copy = $product; foreach ($values as $item) { $copy[$key] = $item; $append[] = $copy; } $values = array_values($values); } $result = array_merge($result, $append); } } return $result; } // 得到sku数组 $skus = cartesianProduct($combinations); // 输出sku数组 print_r($skus);输出结果如下:Array ( [0] => Array ( [颜色] => 红色 [尺寸] => S [版本] => V1 ) [1] => Array ( [颜色] => 红色 [尺寸] => S [版本] => V2 ) [2] => Array ( [颜色] => 红色 [尺寸] => S [版本] => V3 ) [3] => Array ( [颜色] => 红色 [尺寸] => M [版本] => V1 ) [4] => Array ( [颜色] => 红色 [尺寸] => M [版本] => V2 ) [5] => Array ( [颜色] => 红色 [尺寸] => M [版本] => V3 ) [6] => Array ( [颜色] => 红色 [尺寸] => L [版本] => V1 ) [7] => Array ( [颜色] => 红色 [尺寸] => ...
2023年12月28日
6 阅读
0 评论
0 点赞
2023-12-28
一个PHP实现的轻量级简单爬虫
一个PHP实现的轻量级简单爬虫最近需要收集资料,在浏览器上用另存为的方式实在是很麻烦,而且不利于存储和检索。所以自己写了一个小爬虫,在网上爬东西,迄今为止,已经爬了近百万张网页。现在正在想办法着手处理这些数据。爬虫的结构:爬虫的原理其实很简单,就是分析下载的页面,找出其中的连接,然后再下载这些链接,再分析再下载,周而复始。在数据存储方面,数据库是首选,便于检索,而 开发语言,只要支持正则表达式就可以了,数据库我选择了mysql,所以,开发脚本我选择了php。它支持perl兼容正则表达式,连接mysql很方 便,支持http下载,而且windows系统和linux系统都可以部署。正则表达式:正则表达式是处理文字的基本工具,要取出html中的链接和图片,使用的正则表达式如下。代码如下:"#<a1+href=(['\"])(.+)\1#isU" 处理链接"#<img[^>]+src=(['\"])(.+)\\1#isU" 处理图片其他问题: 写爬虫还需要注意的一个问题是,对于已经下载过的url,不能重复进行下载,而有些网页的链接会形成环路,所以需要处理这个问题,我的处理方法是计算已经 处理的url的MD5 值,并存入数据库,这样就可以检验是否已经下载过。当然还有更好的算法,有兴趣的话,可以在网上找一下。相关协议: 爬虫也有自己的协议,有个robots.txt文件定义了那些是网站允许遍历的,但是由于我的时间有限,没有实现这个功能。其他说明: php支持类编程,我写的爬虫主要的类. 1.url处理web_site_info,主要用处理url,分析域名等。2.数据库操作mysql_insert.php,处理和数据库相关的操作。3.历史记录处理,记录已经处理的url。4.爬虫类。存在的问题和不足这个爬虫在小数据量的情况下,运行良好,但是在大数据量的情况下,历史记录处理类的效率就不是很高,通过在数据库结构中,对相关字段进行了索引,速度有了 提高,但是需要不断得读取数据,可能和php本身的array实现有关系,如果一次加载10万条历史记录,速度非常慢。不支持多线程,每次只能处理一个url。php运行本身有内存使用量限制 使用的时候,先在mysql中创建net_spider数据库,然后用db.sql创建相关表。再在config.php中设置mysql 的用户名口令。最后 代码如下:php -f spider.php 深度(数值) url就可以开始工作。代码如下: php -f spider.php 20现在感觉下来,其实做个爬虫没那么复杂,难的是数据的存储和检索。我现在的数据库,最大一个数据表已经15G,正在想办处理这些数据,mysql进 行查询已经感觉有点力不从心了。这点上还真佩服google<?php加载页面function curl_get($url){$ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch,CURLOPT_HEADER,1); $result=curl_exec($ch); $code=curl_getinfo($ch,CURLINFO_HTTP_CODE); if($code!='404' && $result){ return $result; } curl_close($ch);}获取页面url链接function get_page_urls($spider_page_result,$base_url){ $get_url_result=preg_match_all("/<[a|A].*?href=[\'\"]{0,1}([^>\'\"\]*).*?>/",$spider_page_result,$out); if($get_url_result){return $out[1];}else{return;}}相对路径转绝对路径function xdtojd($base_url,$url_list){ if(is_array($url_list)){ foreach($url_list as $url_item){if(preg_match("/^(http:\/\/|https:\/\/|javascript:)/",$url_item)){ $result_url_list[]=$url_item; }else { if(preg_match("/^\//",$url_item)){ $real_url = $base_url.$url_item; }else{ $real_url = $base_url."/".$url_item; } #$real_url = 'http://www.sumpay.cn/'.$url_item; $result_url_list[] = $real_url; }} return $result_url_list; }else{ return; }}删除其他站点urlfunction other_site_url_del($jd_url_list,$url_base){ if(is_array($jd_url_list)){ foreach($jd_url_list as $all_url){echo $all_url; if(strpos($all_url,$url_base)===0){ $all_url_list[]=$all_url; } } return $all_url_list; }else{ return; }}删除相同URLfunction url_same_del($array_url){ if(is_array($array_url)){ $insert_url=array(); $pizza=file_get_contents("/tmp/url.txt"); if($pizza){ $pizza=explode("\r\n",$pizza); foreach($array_url as $array_value_url){ if(!in_array($array_value_url,$pizza)){ $insert_url[]=$array_value_url; } } if($insert_url){ foreach($insert_url as $key => $insert_url_value){ #这里只做了参数相同去重处理 $update_insert_url=preg_replace('/=[^&]*/','=leesec',$insert_url_value); foreach($pizza as $pizza_value){ $update_pizza_value=preg_replace('/=[^&]*/','=leesec',$pizza_value); if($update_insert_url==$update_pizza_value){ unset($insert_url[$key]); continue; } } } } }else{ $insert_url=array(); $insert_new_url=array(); $insert_url=$array_url; foreach($insert_url as $insert_url_value){ $update_insert_url=preg_replace('/=[^&]*/','=leesec',$insert_url_value); $insert_new_url[]=$update_insert_url; } $insert_new_url=array_unique($insert_new_url); foreach($insert_new_url as $key => $insert_new_url_val){ $insert_url_bf[]=$insert_url[$key]; } $insert_url=$insert_url_bf; } return $insert_url;}else{return; }}$current_url=$argv[1];$fp_puts = fopen("/tmp/url.txt","ab");//记录url列表 $fp_gets = fopen("/tmp/url.txt","r");//保存url列表 $url_base_url=parse_url($current_url);if($url_base_url['scheme']==""){ $url_base="http://".$url_base_url['host'];}else{ $url_base=$url_base_url['scheme']."://".$url_base_url['host'];}do{ $spider_page_result=curl_get($current_url); #var_dump($spider_page_result); $url_list=get_page_urls($spider_page_result,$url_base); #var_dump($url_list); if(!$url_list){ continue; } $jd_url_list=xdtojd($url_base,$url_list); #var_dump($jd_url_list); $result_url_arr=other_site_url_del($jd_url_list,$url_base); var_dump($result_url_arr); $result_url_arr=url_same_del($result_url_arr); #var_dump($result_url_arr); if(is_array($result_url_arr)){$result_url_arr=array_unique($result_url_arr); foreach($result_url_arr as $new_url) { fputs($fp_puts,$new_url."\r\n"); }}}while ($current_url = fgets($fp_gets,1024));//不断获得url preg_match_all("/<a1+href=\"'[\"']1+>/",$spider_page_result,$out);echo a hrefvar_dump($out[1]);?>> ↩\"' ↩
2023年12月28日
5 阅读
0 评论
0 点赞
2023-12-28
PHP制作一个简单的日历
PHP制作一个简单的日历实例说明说到对日期和时间的处理,就一定要介绍一下日历程序的编写。但一提起编写日历,大多数读者都会认为日历的作用只是为了在页面上显示当前的日期,其实日历在我们的开发中有着更重要的作用。例如,我们开发一个“记事本”就需要通过日历设定日期,在一些系统中需要按日期去安排任务也需要日历,等等。实现过程将日历类 Calendar 声明在文件 calendar.class.php中,代码如下所示:<?php /* calendar.class.php日历类 声明一个日历类,名称为Calendar,用来显示可以设置日期的日历 */ class Calendar{ private $year;//当前的年 private $month;//当前的月 private $start_weekday;//当月的第一天对应的是周几,作为当月遍历日期的开始 private $days;//当前月的总天数 /** * 构造方法,初始化一些属性 */ function __construct(){ //如果用户没有设置年份数,则使用当前系统时间的年份 $this->year = isset($_GET["year"]) ? $_GET["year"] :date("Y") ; //如果用户没有设置月份数,则使用当前系统时间的月份 $this->month = isset($_GET["month"]) ? $_GET["month"] :date("m") ; //通过具体的年份和月份,利用date() 函数的w参数获取当月第一天对应的是周几 $this->start_weekday = date("w",mktime(0, 0, 0, $this->month, 1, $this->year)); //通过具体的年份和月份,利用date()函数的参数获取当月的天数 $this->days = date("t",mktime(0, 0, 0, $this->month, 1, $this->year)); } /** * 打印整个日历 * @return string 日历字符串 */ function __toString(){ $out .= '<table align="center">'; //日历以表格形式打印 $out .= $this->changeDate(); //用户设置日期 $out .= $this->weeksList(); //打印·周·列表 $out .= $this->daysList(); //打印·日·列表 $out .= '</table>'; //表格结束 return $out; //返回整个日历,输出需要的全部字符串 } /** * 输出周列表 * @return string 周列表字符串 */ private function weeksList(){ $week = array ('日','一','二','三','四','五','六'); $out .= '<tr>'; for($i = 0; $i < count($week); $i++){ $out .= '<th class="fontb">' . $week [$i]. '</th>'; } $out .= '</tr>'; return $out; // 返回周列表字符串 } /** * 输出日列表 * @return string 日历表字符串 */ private function daysList(){ $out .= '<tr>'; // 输出空格(当月第一天对应的是周几,就是几个空格) for($j = 0; $j < $this->start_weekday; $j++){ $out .= '<td> </td>'; } // 循环输出当前月所有日期 for($k = 1; $k <= $this->days; $k++){ $j++; if($k == date('d')){// 若为当前日期,设置为深色背景 $out .= '<td class="fontb">'.$k.'</td>'; } else { $out .= '<td>'.$k.'</td>'; } if($j%7 == 0){//每输出7个日期,就换一行 $out .= '</tr><tr>';//输出行结束和下一行开始 } } while ($j%7 != 0) {//遍历完日期后,剩下的用空格补全 $out .= '<td> </td>'; $j++; } $out .= '</tr>'; return $out; //返回当月日列表 } /** * 用于处理当前年份的上一年需要的数据 * @param int $year 当前年份 * @param int $month 当前月份 * @return string 最终的年份和月份设置参数 */ private function prevYear($year, $month){ $year = $year-1; //上一年是当前年减1 if ($year < 1970){ //如果设至的年份小于1970年 $year = 1970; //年份设置最小值是1970年 } //返回最终的年份和月份设置参数 return "year={$year}&month={$month}"; } /** * 用于处理当前月份的上一月份的数据 * @param int $year 当前年份 * @param int $month 当前月份 * @return string 最终的年份和月份设置参数 */ private function prevMonth($year, $month){ if($month== 1){ $year = $year -1; if($year < 1970){ // 最小年份数不能小于1970年 $year = 1970; } //如果月是1月,上一月就是上一年的最后一月 $month = 12; } else { $month--; //上一月就是当前月减1 } // 返回最终的年份和月份设置参数 return "year={$year}&month={$month}"; } /** * 用于处理当前年份的下一年份的数据 * @param int $year 当前年份 * @param int $month 当前月份 * @return string 最终的年份和月份设置参数 */ private function nextYear($year, $month){ $year = $year+1; // 下一年是当前年加1 if ($year> 2038){ //如果设量的年份大于2038年 $year=2038; //最大年份不能超过2038年 } //返回最终的年份和月份设置参数 return "year={$year}&month={$month}"; } /** * 用于处理当前月份的下一个月份的数据 * @param int $year 当前年份 * @param int $month 当前月份 * @return string 最终的年份和月份设置参数 */ private function nextMonth($year, $month){ if($month == 12){//如果已经是当年的最后一个月 $year++;//下一个月就是下一年的第一个月,让年份加1 if($year> 2038){ //如果设豆的年份大于2038年 $year = 2038; //最大年份不能超过2038年 } $month = 1; //设置月份为下一年的第一个月 } else { $month++;//其他月份的下一个月都是当前月份加1即可 } //返回最终的年份和月份设置参数 return "year={$year}&month={$month}"; } /** * 调整日期 * @param string $url 页面路径 * @return string 页面字符串 */ private function changeDate($url='index.php'){ $out .= '<tr>'; //上一年 $out .= '<td><a href="'.$url.'?'.$this->prevYear($this->year,$this->month).'">'.'<<'.'</a></td>'; //上个月 $out .= '<td><a href="'.$url.'?'.$this->prevMonth($this->year,$this->month).'">'.'<'.'</a> </td>'; $out .= '<td colspan="3">'; $out .= '<form>'; //年份选择框 $out .= '<select name="year" οnchange="window.location=\''. $url.'?year=\'+this.options[selectedIndex].value+\'&month='. $this->month. '\'">'; //循环输出年份 for($sy=1970; $sy <= 2038; $sy++){ $selected = ($sy==$this->year) ? "selected" : ""; $out .= '<option '. $selected. ' value="'. $sy. '">'. $sy. '</option>'; } $out .= '</select>'; //月份选择框 $out .= '<select name="month" οnchange="window.location=\''. $url. '?year='. $this->year. '&month=\'+this.options[selectedIndex].value">'; //循环输出月份 for ($sm=1; $sm <=12; $sm++){ $selected1 = ($sm==$this->month) ? "selected" : ""; $out .='<option '. $selected1. ' value="'. Ssm. '">'. $sm. '</option>'; } $out .= '</select>'; $out .= '</form>'; $out .= '</td>'; //下一年 $out .= '<td> <a href="'.$url.'?'.$this->nextMonth($this->year,$this->month).'">'.'>'.'</a></td>'; //下个月 $out .= '<td> <a href="'.$url.'?'.$this->nextYear($this->year,$this->month).'">'.'>>'.'</a></td>'; $out .= '</tr>'; return $out; //返回调整日期的表单 } }本例将一个日历程序按功能拆分(周列表部分、日期列表部分、设置日期部分,以及上一年、下一年、上一月和下一月的设置部分)并封装在一个日历类中。有了日历类,我们还需要编写一个主程序去加载并输出日历。在主程序中还需要先设置一下日历输出的样式,代码如下所示:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>日历示例</title> <style> table{ border: 1px solid #050; } .fontb{ color:white;background:blue; } th { width: 30px; } td,th { height: 30px;text-align:center; } form { margin: 0px;padding: 0px; } </style> </head> <body> <?php require 'calendar.class.php'; echo new Calendar; ?> </body> </html>效果展示运行效果如下如所示:
2023年12月28日
10 阅读
0 评论
0 点赞
2023-12-28
PHP Base64 、Blob、File间的相互转换
PHP Base64 、Blob、File间的相互转换前言在获取时,遇到需要转换格式的情况,所以记录下来分享。正文一、格式的基本介绍Base64Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法举个例子BlobBlob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream来用于数据操作。举个例子File文件(File)接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。 举个例子就不过多介绍了,主要来讲如果转换。二、如何判断这三种格式1.判断是否为Base64字符串// 判断是否为base64格式字符串 function isBase64(str) { //正则表达式判断 var reg = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i; return reg.test(str) //返回 true or false }2.判断是否为Blob对象console.log(data instanceof Blob) //ture or false3.判断是否为File对象console.log(data instanceof File && !data instanceof Blob) //ture or falsePS:Blob和File都用instanceof来判断是否为对应类型数据有一点需要注意,File对象也是Blob对象 ,因为File继承于Blob,所以其中的判断逻辑可以自己定义。三、格式之间的转换1.Base64转换为Filefunction dataURLtoFile(dataurl, filename) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, { type: mime }); }需要传两个参数,第一个是数据,第二个是自定义文件名字符串2.Base64转换为Blobfunction dataURLtoBlob(dataurl, filename) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }和转File基本一样,就最后一句return不一样3.Blob转Filefunction blobToFile(blob) { return new File([blob], 'screenshot.png', { type: 'image/jpeg' }) }这里和Base64转File其实用的都是new File()这个方法,上面的第二个参数是传进来的,这里是定死的,这个参数不是很重要,可以自行修改函数,方法都已经提供了,直接使用就可以。
2023年12月28日
8 阅读
0 评论
0 点赞
2023-12-28
PHP预处理查询如何防止SQL注入?
PHP预处理查询如何防止SQL注入?目前最有效的防止 sql 注入的方式使用预处理语句和参数化查询。以最常用的 PHP PDO 扩展为例。官方文档中对预处理语句的介绍什么是预处理语句?可以把它看作是想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。预处理语句的两大好处:1.查询仅需解析(或预处理)一次,但可以用相同或不同的参数执行多次。当查询准备好后,数据库将分析、编译和优化执行该查询的计划。对于复杂的查询,此过程要花费较长的时间,如果需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度。通过使用预处理语句,可以避免重复分析 / 编译 / 优化周期。简言之,预处理语句占用更少的资源,因而运行得更快。2.提供给预处理语句的参数不需要用引号括起来,驱动程序会自动处理。如果应用程序只使用预处理语句,可以确保不会发生 SQL 注入。(然而,如果查询的其他部分是由未转义的输入来构建的,则仍存在 SQL 注入的风险)。PDO 的特性在于驱动程序不支持预处理的时候,PDO 将模拟处理,此时的预处理-参数化查询过程在 PDO 的模拟器中完成。PDO 模拟器根据 DSN 中指定的字符集对输入参数进行本地转义,然后拼接成完整的 SQL 语句,发送给 MySQL 服务端。所以,PDO 模拟器能否正确的转义输入参数,是拦截 SQL 注入的关键。小于 5.3.6 的 PHP 版本,DSN (Data Source Name) 是默认忽略 charset 参数的。这时如果使用 PDO 的本地转义,仍然可能导致 SQL 注入。因此,像 Laravel 框架底层会直接设置 PDO::ATTR_EMULATE_PREPARES=false,来确保 SQL 语句和参数值在被发送到 MySQL 服务器之前不会被 PHP 解析。PHP 的实现// 查询 $calories = 150; $colour = 'red'; $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour'); $sth->bindValue(':calories', $calories, PDO::PARAM_INT); $sth->bindValue(':colour', $colour, PDO::PARAM_STR); $sth->execute(); // 插入,修改,删除 $preparedStmt = $db->prepare('INSERT INTO table (column) VALUES (:column)'); $preparedStmt->execute(array(':column' => $unsafeValue));Laravel 的底层实现// 查询的实现 public function select($query, $bindings = [], $useReadPdo = true) { return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { return []; } $statement = $this->prepared( $this->getPdoForSelect($useReadPdo)->prepare($query) ); $this->bindValues($statement, $this->prepareBindings($bindings)); $statement->execute(); return $statement->fetchAll(); }); } // 修改删除的实现 public function affectingStatement($query, $bindings = []) { return $this->run($query, $bindings, function ($query, $bindings) { if ($this->pretending()) { return 0; } $statement = $this->getPdo()->prepare($query); $this->bindValues($statement, $this->prepareBindings($bindings)); $statement->execute(); $this->recordsHaveBeenModified( ($count = $statement->rowCount()) > 0 ); return $count; }); }
2023年12月28日
10 阅读
0 评论
0 点赞
1
...
14
15
16
...
28