今天在写个东西,用到了bootstrap的分裂式下拉菜单,在使用的时候,出现了下面的问题:
折腾了好我,右边的箭头始终无法对齐,把官网的代码复制下来一行一行的删除查找,后面发下是因为没有在html的第一行加上:
<!doctype html>
导致。。。。
他规定了浏览器的解析规范,具体有哪些规范也搞不懂,反正一定要加上就对了。
今天在写个东西,用到了bootstrap的分裂式下拉菜单,在使用的时候,出现了下面的问题:
折腾了好我,右边的箭头始终无法对齐,把官网的代码复制下来一行一行的删除查找,后面发下是因为没有在html的第一行加上:
<!doctype html>
导致。。。。
他规定了浏览器的解析规范,具体有哪些规范也搞不懂,反正一定要加上就对了。
在抓取一些必须用selenium进行抓取的网站时,又想加载速度时,可以按下面的方式去操作
在mac,带参数启动程序:
open -a “Google Chrome” –args -ignore-certificate-errors –proxy-server=127.0.0.1:8080
这里去下载selenium grid
https://www.selenium.dev/downloads/
这里去下载 chrome的webdriver
https://chromedriver.storage.googleapis.com/index.html
再写一个启动脚本:
java -jar ./selenium-server-4.1.2.jar standalone
使用mitmproxy来过滤掉一些无用的请求
安装 pip3 install mitmporxy
写一个过滤脚本: filter_rewardstyle.com.py
import re from mitmproxy import ctx, http # def http_connect(flow: http.HTTPFlow): # if "rewardstyle.com" not in flow.request.host: # ctx.log("忽略connect请求:"+flow.request.url) # flow.response = http.Response.make(404) # return def request(flow: http.HTTPFlow): ctx.log("============ request: " + flow.request.url) if "rewardstyle.com" not in flow.request.host: if re.search(r'\.(css|js|jpg|png|gif|woff|tiff|ico)$', flow.request.url): ctx.log("忽略资源:"+flow.request.url) flow.response = http.Response.make(404) return def response(flow): # ctx.log(flow.request.url) """修改应答数据""" if "rewardstyle.com" not in flow.request.url: flow.response.text = "by mitmproxy"
运行这个命令:
mitmdump -s filter_rewardstyle.com.py
来源,原站已无法打开
https://www.im050.com/posts/390
首先通过strace
命令跟踪假死进程的系统调用信息
strace -p 16618
执行以上命令后,得到如下结果
poll([{fd=33, events=POLLOUT|POLLWRNORM}], 1, 0) = 0 (Timeout) poll([{fd=33, events=POLLOUT}], 1, 1000) = 0 (Timeout) poll([{fd=33, events=POLLOUT|POLLWRNORM}], 1, 0) = 0 (Timeout) poll([{fd=33, events=POLLOUT}], 1, 1000) = 0 (Timeout)
Tips: 通过命令
man poll
可以查看poll系统调用的函数原型
发现当前进程占用了33
的文件描述符,接着可以通过下面的命令列出占用该文件描述符的进程
lsof -d 33 | grep php
得到如下结果
php 16618 root 33u IPv4 987105 0t0 TCP iZbp10yq5syyio54pew3swZ:56030->192.168.110.2:http (SYN_SENT)
可以看到当前进程正在进行http
请求,并且处于SYN_SENT
的状态 (长期处于该状态),最后猜想可能是由于curl
没有设置超时时间,服务器没有及时反应或无法响应的情况下造成了假死现象。
经过调整之后,进程运行正常。
/** * 获取当前程序运行了多少个进程 * @param $processName 程序进程名,要唯一 */ function GetInstancePids($processName) { // 把文件放到外面去,防止发布版本把状态文件搞没了 $dir = dirname(dirname(dirname(dirname(__FILE__)))).'/data'.'/pids'; $file = $dir . DIRECTORY_SEPARATOR . $processName; $pinfo = getCurrentProcessInfo(); if (!file_exists($file)) { file_put_contents($file, "{$pinfo['pid']}\t{$pinfo['cmd']}\n"); return true; } $i = 0; $pidfile = fopen($file, 'r+'); do { if (flock($pidfile, LOCK_EX)) { break; } else { if ($i++ == 10) { exit('try 10 times to lock pid file,faild'); } usleep(1000); } } while (true); $read = fread($pidfile, 10240); rewind($pidfile); $read = explode("\n", trim($read)); $process_info = []; foreach ($read as $index => $line) { list($pid, $cmd) = explode("\t", $line); if (!empty($pid) && isPidExists($pid, $cmd)) { $process_info[] = "{$pid}\t{$cmd}"; } } $process_info[] = "{$pinfo['pid']}\t{$pinfo['cmd']}"; ftruncate($pidfile,0); fwrite($pidfile, implode("\n", $process_info)); fflush($pidfile); flock($pidfile, LOCK_UN); fclose($pidfile); return true; } /** * 返回自身进程信息 */ function getCurrentProcessInfo() { $mypid = getmypid(); $outputs = []; exec('ps -ax | grep -E "^\s*' . $mypid . '\s+"', $outputs); $matched = []; preg_match('/^\s*(\S+?)\s+?\S+?\s+?(\S+?)\s+?\S+?\s+?(.+)/', $outputs[0], $matched); return [ 'pid' => $matched[1], 'uptime' => $matched[2], 'cmd' => $matched[3], ]; } function isPidExists($pid, $cmd) { exec('ps -ax | grep -E "^\s?'. $pid . '.+?'.$cmd.'"', $result); return isset($result[0]); }
使用的时候:
$pids = GetInstancePids(“xxx”);
if (count($pids) > 1) die(“程序运行中”);
转自:https://www.cnblogs.com/qinyujie/p/8979464.html
语法规则: location [=|~|~*|^~] /uri/ { … }
=
开头表示精确匹配^~
开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)。以xx开头~
开头表示区分大小写的正则匹配 以xx结尾~*
开头表示不区分大小写的正则匹配 以xx结尾!~
和!~*
分别为区分大小写不匹配及不区分大小写不匹配 的正则/
通用匹配,任何请求都会匹配到。location = / { # 精确匹配 / ,主机名后面不能带任何字符串 [ configuration A ] } location / { # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求 # 但是正则和最长字符串会优先匹配 [ configuration B ] } location /documents/ { # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索 # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条 [ configuration C ] } location ~ /documents/Abc { # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索 # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条 [ configuration CC ] } location ^~ /images/ { # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。 [ configuration D ] } location ~* \.(gif|jpg|jpeg)$ { # 匹配所有以 gif,jpg或jpeg 结尾的请求 # 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则 [ configuration E ] } location /images/ { # 字符匹配到 /images/,继续往下,会发现 ^~ 存在 [ configuration F ] } location /images/abc { # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在 # F与G的放置顺序是没有关系的 [ configuration G ] } location ~ /images/abc/ { # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用 [ configuration H ] } location ~* /js/.*/\.js
= 开头表示精确匹配
^~ 开头表示url以某个常规字符串开头,理解为匹配url路径即可,nginx不对url做编码,因此请求为/static/20%/aa,可以被规则 ^$ /static/ /aa 匹配到
~ 区分大小写的正则匹配
~* 不区分大小写的正则匹配
!~ !~* 区分大小写不匹配及不区分大小写不匹配的正则
/ 通用匹配,任何请求都会匹配到
location = / {多个location配置的情况下匹配顺序为首先匹配 = 其次匹配 ^~ 其次是按文件中的顺序的正则匹配,最后是交给 / 通用匹配。 当匹配成功的时候,停止匹配,按当前匹配规则处理请求。
#规则A } location = /login { #规则B } location ^~ /static/ { #规则C } location ~ \.(gif|jpg|png|js|css)$ { #规则D } location ~* \.png$ { #规则E } location !~ \.xhtml$ { #规则F } location !~* \.xhtml$ { #规则G } location / { #规则H }
那么产生的效果如下:
访问根目录/, 比如http://localhost/ 将匹配规则A
访问 http://localhost/login 将匹配规则B,http://localhost/register 则匹配规则H
访问 http://localhost/static/a.html 将匹配规则C
访问 http://localhost/a.gif, http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用,而http://localhost/static/c.png 则优先匹配到规则C
访问 http://localhost/a.PNG 则匹配规则E,而不会匹配规则D,因为规则E不区分大小写。
访问 http://localhost/a.xhtml 不会匹配规则F和规则G,http://localhost/a.XHTML不会匹配规则G,因为不区分大小写。规则F,规则G属于排除法,符合匹配规则但是不会匹配到,所以想想看实际应用中哪里会用到。
访问 http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候应该是nginx转发请求给后端应用服务器,比如FastCGI(php),tomcat(jsp),nginx作为反向代理服务器存在。
所以实际使用中,个人觉得至少有三个匹配规则定义,如下:
直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
这里是直接转发给后端应用服务器了,也可以是一个静态首页
第一个必选规则
location = / {
proxy_pass http://tomcat:8080/index
}
第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
root /webroot/static/;
}
location ~* .(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}
第三个规则就是通用规则,用来转发动态请求到后端应用服务器
非静态文件请求就默认是动态请求,自己根据实际把握
毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了
location / {
proxy_pass http://tomcat:8080/
}
rewrite功能就是,使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。rewrite只能放在server{},location{},if{}中,并且只能对域名后边的除去传递的参数外的字符串起作用,例如 http://seanlook.com/a/we/index.php?id=1&u=str 只对/a/we/index.php重写。语法rewrite regex replacement [flag];
如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。
表明看rewrite和location功能有点像,都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,可以proxy_pass到其他机器。很多情况下rewrite也会写在location里,它们的执行顺序是:
执行server块的rewrite指令
执行location匹配
执行选定的location中的rewrite指令
如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件;循环超过10次,则返回500 Internal Server Error错误。
server { listen 80; server_name start.igrow.cn; index index.html index.php; root html; if ($http_host !~ “^star\.igrow\.cn$" { rewrite ^(.*) http://star.igrow.cn$1 redirect; } }
last – 基本上都用这个Flag。
break – 中止Rewirte,不在继续匹配
redirect – 返回临时重定向的HTTP状态302
permanent – 返回永久重定向的HTTP状态301
因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。这里 last 和 break 区别有点难以理解:
last一般写在server和if中,而break一般使用在location中
last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配
break和last都能组织继续执行后面的rewrite指令
语法为if(condition){…},对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行,if条件(conditon)可以是如下任何内容:
当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false
直接比较变量和内容时,使用=或!=
~正则表达式匹配,~*不区分大小写的匹配,!~区分大小写的不匹配
1、下面是可以用来判断的表达式:
-f和!-f用来判断是否存在文件
-d和!-d用来判断是否存在目录
-e和!-e用来判断是否存在文件或目录
-x和!-x用来判断文件是否可执行
2、下面是可以用作判断的全局变量
if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /msie/$1 break; } //如果UA包含"MSIE",rewrite请求到/msid/目录下 if ($http_cookie ~* "id=([^;]+)(?:;|$)") { set $id $1; } //如果cookie匹配正则,设置变量$id等于正则引用部分 if ($request_method = POST) { return 405; } //如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302 if ($slow) { limit_rate 10k; } //限速,$slow可以通过 set 指令设置 if (!-f $request_filename){ break; proxy_pass http://127.0.0.1; } //如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查 if ($args ~ post=140){ rewrite ^ http://example.com/ permanent; } //如果query string中包含"post=140",永久重定向到example.com location ~* \.(gif|jpg|png|swf|flv)$ { valid_referers none blocked www.jefflei.com www.leizhenfang.com; if ($invalid_referer) { return 404; } //防盗链 } 例:http://localhost:88/test1/test2/test.php $host:localhost $server_port:88 $request_uri:http://localhost:88/test1/test2/test.php $document_uri:/test1/test2/test.php $document_root:D:\nginx/html $request_filename:D:\nginx/html/test1/test2/test.php
location ~* \.(gif|jpg|swf)$ { valid_referers none blocked start.igrow.cn sta.igrow.cn; if ($invalid_referer) { rewrite ^/ http://$host/logo.png; } }
location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ { if (-f $request_filename) { expires 1h; break; } }
$args : #这个变量等于请求行中的参数,同$query_string $content_length : 请求头中的Content-length字段。 $content_type : 请求头中的Content-Type字段。 $document_root : 当前请求在root指令中指定的值。 $host : 请求主机头字段,否则为服务器名称。 $http_user_agent : 客户端agent信息 $http_cookie : 客户端cookie信息 $limit_rate : 这个变量可以限制连接速率。 $status 请求状态 $body_bytes_sent 发送字节 $request_method : 客户端请求的动作,通常为GET或POST。 $remote_addr : 客户端的IP地址。 $remote_port : 客户端的端口。 $remote_user : 已经经过Auth Basic Module验证的用户名。 $request_filename : 当前请求的文件路径,由root或alias指令与URI请求生成。 $scheme : HTTP方法(如http,https)。 $server_protocol : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。 $server_addr : 服务器地址,在完成一次系统调用后可以确定这个值。 $server_name : 服务器名称。 $server_port : 请求到达服务器的端口号。 $request_uri : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。 $uri : 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。 $document_uri : 与$uri相同。
apcu是以前的apc的升级,apcu实现了基于本机内存的高效缓存,类似的还有鸟哥的yac,但yac是无锁的性能更好一些。
单个设置缓存
apcu_store(‘key’, ‘value’, 3600);
批量设置缓存
apcu_store([‘key1’=>’value1’, ‘key2’=>’value2], NULL/*这个变量没用*/, 3600);
单个获取,没取到时,返回false
apcu_fetch(‘key’);
批量获取,以数组的格式返回,一个都没有取到时,返回空数组,好像不会返回false
apcu_fetch([‘test’, ‘test2’, ‘noExits’])
批量获取时,如果某一个key不存在,则不会返回在数组中。
从网页上批量获取数据
Array.prototype.forEach.call($$(‘#filter-accordion-0 > web-category-tree-v2 > ul > li > a’), function (a) {
console.log(a.href);
});
selector用$$(),xpath用$x()
目录结构
{ "name": "myjoyoo/affiliate-sdk", "description": "如LinkShare、CJ、PJ、Awin之类的联盟的SDK接口封装", "type": "l", "require": { "php": ">=8.0", "guzzlehttp/guzzle": "^7.3", "nesbot/carbon": "^2.48" }, "license": "Apache", "authors": [ { "name": "myjoyoo", "email": "[email protected]" } ], "minimum-stability": "dev", "autoload": { "psr-4": { "AffiliateSDK\\": "src" }, "files": ["src/include/commonFunction.php"] } }
改了之后,需要执行下面的命令去生效
composer dump-auotload
Ins Api调用说明
Ins分2种用户,一种是普通的,一种是专业的,普通用户是无法满足我们需求的。
专业用户需要满足以下准备工内容:
1、一个Ins的商务账户
2、一个Facebook开发者账号
3、Facebook开发者中心建立一个App并审核通过(注意APP的类型要选择为business)
4、增加2个Product,一个facebook登录和instagram graph api
5、在app preview里去选择”pages_show_list”和”instagram_basic” 2个权限,具体别的权限看情况去选择,在正式使用之前需要要去申请这些权限。
开始,参照:https://developers.facebook.com/docs/instagram-api/getting-started
把个人的Ins账户转为专业账户
关联 https://help.instagram.com/399237934150902?fbclid=IwAR1VFQ403f16ZUvApnMtsDYuNRHcwg9il0qh4G5DDluZHNSfJU3wKK4-Zb4
登录FaceBook账户指南
https://developers.facebook.com/docs/facebook-login/web
通过php登录的话,要参考github上的代码:
https://github.com/facebookarchive/php-graph-sdk/tree/master
有一个坑是要开启session,sdk是通过session来判断state参数是否一样的,这样防止非法调用
我们需要用到这个instagram_basic api的权限,需要进行“business verification”,
https://developers.facebook.com/docs/permissions/reference/instagram_basic
验证的帮助说明在这里:
https://developers.facebook.com/docs/development/release/business-verification
验证步骤:
https://developers.facebook.com/apps/305829777821658/app-review/submissions/current-request/?business_id=219068326242405
在提交审核的时候,有一个deletion url,是当对方删除数据的时候,我们也要一起删除,见:
https://developers.facebook.com/docs/development/create-an-app/app-dashboard/data-deletion-callback
API的调用参考:https://developers.facebook.com/docs/instagram-api/getting-started
获取用户信息
https://graph.facebook.com/v11.0/me/accounts?access_token=
获取用户在IG里的信息
https://graph.facebook.com/v11.0/103288701887981?fields=instagram_business_account&access_token={access-token}
根据IG ID获取用户在IG里的信息
https://graph.facebook.com/v3.2/17841405339389255?fields=biography,id,username,website,followers_count,follows_count,media_count,profile_picture_url&access_token=
获取用户的IG Media列表
https://graph.facebook.com/v11.0/17841405339389255/media?access_token=
根据IG的ID获取详情
https://graph.facebook.com/v11.0/17912414743825369?fields=id,media_type,like_count,comments_count,media_url,owner,timestamp&access_token=
格式化:select DATE_FORMAT(now(), ‘%Y-%m-%d %T’);
从1970年1月1日到指定时间的天数:select to_days(now());
取当前时间:
select now(), current_timestamp(),current_timestamp,current_time, curtime(),current_date, curdate(), sysdate();
sysdate()函数是这个函数执行时候的时间,其它的是语句开始执行的时间。
时间的加减:
DATE_ADD(date,INTERVAL expr type)
DATE_SUB(date,INTERVAL expr type)
DATEDIFF(date1,date2),2个时间的天数
TIMESTAMPDIFF(type,date1,date2),2个时间的差额
TIMESTAMPADD(type,int_expr,date1),加时间
存储过程
set @var = ''; set @var2 = 'fff'; set @var = @var2; -- 这种只能用在declare了的变量 set var = 'sdfdf'; -- 这里不会输出返回结果,只会设置变量 select `day` into @var from redash_queue_flush_sem_base_data limit 1; -- 这里在设置变量的同时,也会返回 select @day:=`day` from redash_queue_flush_sem_base_data limit 1; CREATE DEFINER=`dealam_stat_prod`@`%` PROCEDURE `flush_sem_base_data`() -- 注意这里的BYEBYE,在里面用leave BYEBYE就可以退出了,存储过程里没有return之类的功能 BYEBYE:BEGIN declare vday varchar(100); declare vvar VARCHAR(50); declare vvalue VARCHAR(200); declare select_done int default 0; -- 定义select游标 declare cur_queue cursor for select `var`, `value` from redash_variable limit 2; -- 定义游标是否循环完成的标记变量 declare continue handler for not found set select_done = 1; if @queue_count > 0 then insert into redash_logs (`what`) values (concat('刷新队列里还有数据:', @queue_count)); select concat('刷新队列里还有数据:', @queue_count) as msg; leave BYEBYE; else -- 找出待更新订单对应的订单日期,放入待刷新队列中 insert ignore redash_queue_flush_sem_base_data select distinct(from_unixtime(transaction_time, '%Y-%m-%d')) from da_sem_order where updated_time>@sem_last_update_time order by updated_time; end if; open cur_queue; loop_label:loop -- 注意这里变量前没有加@ fetch cur_queue into vvar, vvalue; -- select_done 前没有加@ if select_done = 1 then leave loop_label; end if; -- 注意这里变量前也没有加@,也就是说如果是declare的变量,好像是不用加的 select vvar, vvalue; set @vvar2 = vvar; select @vvar2; insert into redash_logs (`what`) values (concat('刷新了sem base data,日期:', vvar)); end loop; END
查看未提交的事务
select trx_state, trx_started, trx_mysql_thread_id, trx_query from information_schema.innodb_trx\G;
查看锁信息
select * from information_schema.INNODB_TRX WHERE trx_state=’LOCK WAIT’\G