您的位置:首页 > 业界新闻

互联网业界经典 经典业务 经典需求 经典分析 经典方案 经典代码 经典呈现 经典片段 PHP经典案例

2015-01-16 19:53 816 查看
Tips:这里讨论的都是百万级,千万级,亿万级的大数据,而且是生产环境条件下的问答。

1.如何大批量更新、删除、插入数据到数据库或者在线大批量的发邮件?

想确保大批量数据原子性,协同办公不冲突,进阶教程请看这里

//根据条件,每批执行100个,如果你的数据库够强悍,数值可以调大
//无限循环执行,直到执行完毕!
//每次都从0开始分页,从而巧妙的避免了当Mysql的OFFSET值过大导致分页慢的性能问题
$sql = 'SELECT `id`, `text` FROM `table` WHERE `state` = 0 LIMIT 0, 100';
while(!($result = $db->fetchAll($sql))){
foreach($result as $k => $v){
echo 'k:'.$k.PHP_EOL.'v:'.$v.PHP_EOL;
$db->update('table', array('state' => 1), 'id = '.$k.'');//将已执行的标记为1
//insert db where id = '.$v['id'].'...
//update db where id = '.$v['id'].'...
//delete db where id = '.$v['id'].'...
//mail();//发送邮件给用户...
usleep(mt_rand(1000, 1000000));//随机间歇休息一时,防止服务器卡死
}
}
echo '执行完毕!';
exit();


2.针对展示不稳定的网站数据如何采集?

$flag = false;

while(!$flag){
$content = curl('http://my.oschina.net/cart/');
if(stripos($content, '你指定的识别是否采集到你想要的内容的字符串') !== false){
$flag = true;
}
}
echo $flag ? '哈哈,我抓到你啦.' : '采集失败!';
exit();


3.针对有防采集规则的网站如何采集,如何更好的模拟浏览器执行和真实的用户行为?

//更形象的模拟浏览器,代码如下:
//必选:开启session
@session_start();

//必选:模拟cookie
curl_setopt($curl, CURLOPT_COOKIEJAR, getcwd().'/cookies.txt');
curl_setopt($curl, CURLOPT_COOKIEFILE, getcwd().'/cookies.txt');
curl_setopt($curl, CURLOPT_COOKIE, session_name().'='.session_id().'; a=1; b=2; c=3');

//必选:模拟浏览器
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/'.mt_rand(1, 9).'.0 (Windows NT '.mt_rand(1, 9).'.'.mt_rand(1, 9).'; rv:'.mt_rand(1, 100).'.'.mt_rand(1, 9).') Gecko/20100101 Firefox/'.mt_rand(1, 9).'0.'.mt_rand(1, 9).'');

//必选:模拟访客IP、header等真实请求信息
curl_setopt($curl, CURLOPT_HTTPHEADER, array (
'Accept: text/html,application/xhtml+xml,application/xml;q=0.'.mt_rand(1, 9).',*/*;q=0.'.mt_rand(1, 9).'',
'Accept-Language: en-us,en;q=0.'.mt_rand(1, 9).'',
'Cache-Control: max-age=0',
'Connection: keep-alive',
'Pragma: no-cache',
'X-Forwarded-For: '.mt_rand(0, 255).'.'.mt_rand(0, 255).'.'.mt_rand(0, 255).'.'.mt_rand(0, 255),
'Client_Ip: '.mt_rand(0, 255).'.'.mt_rand(0, 255).'.'.mt_rand(0, 255).'.'.mt_rand(0, 255),
));

//可选项:更高级的用户可使用代理采集
curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
curl_setopt($curl, CURLOPT_PROXY, '127.0.0.1:8080');//代理ip自己去搜索引擎搜

//必选:更真实的用户行为
usleep(mt_rand(1000000, 3000000));//随机间歇休息一时

//把上述代码加到执行采集curl_exec($curl)前面即可!
//切记:执行curl_exec($curl) 和 上述代码的次数一定是一样的!
//也就是说,每次开始新的抓取curl_exec($curl)前,必须再次加载上述代码!原因自己想^.^


4.如何在foreach时使用中间临时变量数组时候节省内存开销?

节省内存方法1:使用 PHP 生成器yield的使用【PHP 5.5.0+】

节省内存方法2:使用 PHP引用

$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // 最后取消掉引用


5.如何快速的从Mysql数据库中随机取出指定数量的数据?

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


6.针对PHP业界公认的一些函数漏洞有什么解决方案?

//strip_tags:替代方案

class PHP
{
public static function strip_tags(&$str, $default = false){
return filter_var($str, FILTER_SANITIZE_STRING, array('options' => array('default' => $default)));
}
}

var_dump(PHP::strip_tags('这里是不完整的HTML标签或者单引号、双引号没有成对出现。。。'));

//ip2long:替代方案

class PHP
{
public static function ip2long(&$ip){
return sprintf('%u', ip2long($ip));
}
}

var_dump(PHP::ip2long('192.168.1.1'));

//nl2br:替代方案

class PHP
{
public static function nl2br(&$str){
return str_replace(array("\r\n", "\r", "\n"), '
', $str);
}
}

var_dump(PHP::nl2br('h
ello'));

//crc32:替代方案

class PHP
{
public static function crc32(&$url){
return sprintf('%u', crc32($url));
}
}

var_dump(PHP::crc32('http://my.oschina.net/cart/'));


7.如何更优雅更高效的定义常量?

const SPIDER_URL = 'http://my.oschina.net/cart/';

const SPIDER_CATEGORY_LIST = array(1,2,3);

const SPIDER_CATEGORY_ID = 118;


8.如何更优雅的解决时间8小时问题?

PHP时间 相差8小时的8从何而来?如何得到正确的时区?如何优雅的处理时间

@ini_set('date.timezone','PRC');


9.如何更优雅的智能加载PHP类库文件?

//假设你的库文件目录

E:\php\data\library

//你的当前执行的index.php文件目录

E:\php\data\localweb\tools

//那么,你在E:\php\data\localweb\tools\index.php

//可加入以下代码,就直接可以使用你的类库了,无include,无require,APC下,性能更卓越!

//智能加载
function autoload($class) {
set_include_path('../../library/');
spl_autoload($class);
}
spl_autoload_register('autoload');

///////////////////////////////////////////

echo 'Hello,word!';

echo Tools::formatUrl('http://my.oschina.net/cart/');

$tools = new Tools();
var_dump($tools->info());


10.如何尽量避免写foreach?

array_column【PHP 5.5.0+】

array_map

array_walk

var_dump(array_column(array(array('id' => '1','address' => '127.0.0.1:8080'),array('id' => '2','address' => '127.0.0.1:9090')), 'address', 'id'));


11.如何高效的在线解压、打包压缩包文件?

PHP ZIP扩展【PHP 5.2.0+】

//在线解压
function ZipExtract($from_file, $to_dir){
if (!is_dir($to_dir)){
mkdir($to_dir, 0777);
}
$zip = new ZipArchive();
if ($zip->open($from_file) === true && $zip->extractTo($to_dir) && $zip->close()){
return true;
}
return false;
}

//压缩打包
$zip = new ZipArchive();
$ret = $zip->open('application.zip', ZipArchive::OVERWRITE);
if ($ret !== TRUE) {
printf('Failed with code %d', $ret);
} else {
$options = array('add_path' => 'sources/', 'remove_all_path' => TRUE);
$zip->addGlob('*.{php,txt}', GLOB_BRACE, $options);
$zip->close();
}


12.如何更高效的使用临时表?

使用mysql内存表,MEMORY



13.如何更高效的执行替换?

str_replace(array('a', 'b', 'c'), array('aa', 'bb', 'cc'), $str);
str_replace(array(123, 456, 789), array(11, 22, 33), $str);
str_replace(array('/(\d+)/isu', 'a', 'b'), array('数字被正则替换了', '普通替换A', '普通替换B'), $str);


14.Mysql字段明明设置了longtext类型为什么存入时丢失数据?

尽管你设置了以下代码

//PHP文件本身编码
@ini_set('default_charset', 'utf-8');

//数据库编码
$db = new Db('mysql:host=localhost;dbname=spider', 'root', '123', array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''));


现象:

导致了我们看到的文件只存入一半,数据库longtext类型丢失内容的现象

解决方法分2种:

1.因为大文件内容中有些非utf8字符导致入库失败,需要针对你入库的字符串进行强制转码:

iconv('utf-8', "utf-8//IGNORE", $data);
或者
mb_convert_encoding($string, 'utf-8', 'utf-8');

2.数据库字段编码的utf8_general_ci改为utf8mb4_general_ci,如emoji表情符号,就是4字节!


15.Mysql如何快速高效的执行分页?

MYSQL 分页慢加速器 解决方案 MYSQL 分页优化 MYSQL 分页解决方案 LIMIT 优化

SELECT `id` , `url` , `content` FROM product INNER JOIN (SELECT `id` FROM product ORDER BY `id` LIMIT 10000 , 100) AS product2 USING ( id );


16.针对采集目录页不提供产品数量的页面如何计算分页总数?

//原理:一般网站,当你访问1个不存在的目录分页时,都会展示最后1个分页内容,从而提取最后1页的分页数目

//操作:

//采集1个非常大的分页数值的分页URL,如:http://www.xxx.com/p/100000
//然后根据采集的内容从中提取最后一页的分页数字


17.如何避免一个需求被执行多遍?同个需求如何让同事帮我协同办公?

Mysql Innodb 事务在业务中的具体使用案例 + Demo演示

//数据库必须是innodb类型

//使用事务+执行标记do来实现我们的需求
$db->beginTransaction();//开启事务

$sql = 'SELECT `id`, `url`, `content` FROM `table` WHERE `do` = 0 LIMIT 0, 100 FOR UPDATE';//获取未执行的记录
$urlArray = $db->fetchAll($sql);

$times = 1;
while(!empty($urlArray)){
foreach($urlArray as $v){
//do somthing....
$db->update('table', array('do' => 1, 'url' => $v['url']), '`id` = ' . $v['id']);//已执行

echo $v['id'].' OK. '.PHP_EOL;
}

//递归中 提交事务
if(!$db->commit()){
$db->rollBack();
echo '['.$times.']. Times OK.'.PHP_EOL;
}else{
echo '['.$times.']. Times No...'.PHP_EOL;
}

//递归中 开始事务
$db->beginTransaction();
$urlArray = $db->fetchAll($sql);
$times++;
}

//提交事务
if(!$db->commit()){
$db->rollBack();
echo 'OK.'.PHP_EOL;
}else{
echo 'No...'.PHP_EOL;
}

echo '协同办公,执行完毕!';


18.如何在PHP采集中批量随机模拟客户IP地址?

echo join('.', array(mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)));


19.如何在Mysql插入时1条inser批量高效插入大数据?

PHP大数组下,避免Mysql逐条执行,可以分批执行,提高代码效率

$db->query('INSERT INTO `myTable` (`address`) VALUES '.join(',', array_map(function($ip, $port){return '("'.($ip.':'.$port).'")';}, $ipArray[0], $ipArray[1])).';');

注意,你的$ipArray数据格式为:

$ipArray = array(array('127.0.0.1','192.168.1.1'), array('80','443'));


20.如何在采集时勿让程序太频繁采集目标站点,需控制采集频率?

usleep(mt_rand(1000, 1000000));//单位是微妙


21.如何用一句话PHP代码实现复杂的业务逻辑?

//1.定义文件名
//2.判断文件存不存在
//3.如果存在,则引用文件
//4.如果不存在,则输出退出语句

(is_file($configFile = 'config.inc.php') && require($configFile)) || exit('The configuration file "'.$configFile.'" does not exist!');


22.如何通过GET方式URL传递数组形式的参数?

http://127.0.0.1/?a[]=1&a[]=2&a[]=3
//这也给我们提了个醒,get等外部提交来的参数的值除了常规的字符串、空、null,还有数组!记得过滤、限制即可,如:
//is_string($_GET['a'])
//is_array($_GET['a'])
//(string)$_GET['a']
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐