实践篇
约 1451 字大约 5 分钟
2025-07-07
微信实际支付成功, 但回调失败如何处理?
临时页面处理:在返回页增加 “支付成功” 与 “遇到问题, 联系客服” 按钮选项。这两个按钮都重新调取微信获取支付结果的接口,成功或失败都跳转一个中间页。
定时处理:如没有临时页, 则根据业务情况, 设置合适的回调周期, 周期性的调取 “获取微信支付结果的接口” , 将支付结果更新至数据库。
如何获取客户端 IP 与服务端 IP
# 客户端IP
$_SERVER['REMOTE_ADDR']
# 服务端IP
$_SERVER['SERVER_ADDR']
# 客户端IP(代理穿透)
$_SERVER['HTTP_X_FORWARDED_FOR']
/*
* 获取客户端IP地址
* @return string
*/
function get_client_ip() {
if(getenv('HTTP_CLIENT_IP')){
$client_ip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR')) {
$client_ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR')) {
$client_ip = getenv('REMOTE_ADDR');
} else {
$client_ip = $_SERVER['REMOTE_ADDR'];
}
return $client_ip;
}
/* 获取服务器端IP地址
* @return string
*/
function get_server_ip() {
if (isset($_SERVER)) {
if($_SERVER['SERVER_ADDR']) {
$server_ip = $_SERVER['SERVER_ADDR'];
} else {
$server_ip = $_SERVER['LOCAL_ADDR'];
}
} else {
$server_ip = getenv('SERVER_ADDR');
}
return $server_ip;
}
不使用临时变量交换两个变量的值
list($a, $b) = array($b, $a);
# 或 数组下标
$array[0] = $a;
$array[1] = $b;
$a = $array[1];
$b = $array[0];
通过 $_FILES 获取上传文件类型可能受到黑客伪造, 如何判断用户上传的图像文件类型真实可靠
- getimagesize 函数获取的数组结果下标为 2 的值代表文件的类型。
1 = GIF, 2 = JPG, 3 = PNG, 4 = SWF, 5 = PSD, 6 = BMP, 7 = TIFF(intel byte order), 8 = TIFF(motorola byte order), 9 = JPC, 10 = JP2, 11 = JPX, 12 = JB2, 13 = SWC, 14 = IFF, 15 = WBMP, 16 = XBM,
短信验证码防刷机制
- 前端时间控制:60 秒后才能再次发送,但刷新页面就会又能发送
- Token 校验:校验通过才发送,这时还可以将 60 秒缓存
- 图形验证码限制
- 次数限制:根据业务场景,例: 同一手机号,24小时内不可超过5条
- 相同返回:例: 30 分钟之内,如果验证码未使用,则返回同一个验证码
- 短信预警机制:例:检测短时发送量,达到预警值,就给管理员发送提醒。
- IP限制
如何实现 session 共享
- 将 session 持久化至数据库
- 将 session 保存 至 Redis、Memcache
PHP 如何解决跨域问题?
# 1. 代理, 由 php 调用 php 接口
# 2. Nginx 反向代理
# 3. 允许所有域名访问
header(“Access-Control-Allow-Origin:*”);
header(‘Access-Control-Allow-Methods:POST’);// 表示只允许POST请求
header(‘Access-Control-Allow-Headers:x-requested-with, content-type’);
# 4. 允许单个域名访问
header(‘Access-Control-Allow-Origin:http://www.test.cn‘);
header(‘Access-Control-Allow-Methods:POST’); //表示只允许POST请求
header(‘Access-Control-Allow-Headers:x-requested-with, content-type’); //请求头的限制
# 5. 允许多个域名访问
$array = ['域名1', '域名2'];
public function setheader()
{
// 获取当前跨域域名
$origin = isset($_SERVER[‘HTTP_ORIGIN’]) ? $_SERVER[‘HTTP_ORIGIN’] : ‘’;
if (in_array($origin, $array)) {
header(‘Access-Control-Allow-Origin:’ . $origin); # 允许 $array 数组内的域名跨域访问
header(‘Access-Control-Allow-Methods:POST,GET’); # 响应类型
header(‘Access-Control-Allow-Credentials: true’); # 带 cookie 的跨域访问
header(‘Access-Control-Allow-Headers:x-requested-with,Content-Type,X-CSRF-Token’); # 响应头设置
}
}
字符串反转
<?php
function str_rev ($str) {
# true 模拟死循环, $i 为长度
for ($i = 0; true; $i++) //true模拟死循环
{
if (!isset($str[$i])) break;
}
$return_str = '';
for ($j = $i - 1; $j >=0 ; $j -- )
{
$return_str .= $str[$j];
}
return $return_str;
}
# 或
function str_rev($str,$encoding='utf-8'){
$result = '';
$len = mb_strlen($str);
for($i=$len-1; $i>=0; $i--){
$result .= mb_substr($str,$i,1,$encoding);
}
return $result;
}
自己写一个获取字符串长度的函数
function strlen($str) {
if ($str == '') return 0;
$count = 0;
while (1){
if ($str[$count] != NULL){
$count++;
continue;
}else{
break;
}
}
return $count;
}
写一个可以从 URL 链接中取出文件扩展名的函数
function getExt($url)
{
$arr = parse_url($url);//parse_url解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分
//'scheme' => string 'http' (length=4)
//'host' => string 'www.sina.com.cn' (length=15)
//'path' => string '/abc/de/fg.php' (length=14)
//'query' => string 'id=1' (length=4)
$file = basename($arr['path']);// basename函数返回路径中的文件名部分
$ext = explode('.', $file);
return $ext[count($ext)-1];
}
PHP遍历文件夹
- 遍历某一个目录下面的文件和文件夹
$dir = __DIR__;
if (is_dir($dir)) {
$array = scandir($dir, 1);
foreach($array as $key => $value) {
if ($value == '.' || $value == '..') {
unset($array[$key]);
continue;
}
}
} else {
echo '不是一个目录';
}
print_r($array);
- 写出一个函数对文件目录坐遍历
function loopDir($dir){
$handle = opendir($dir);
while(false !==($file =readdir($handle))){
if($file!='.'&&$file!='..'){
echo $file."<br>";
if(filetype($dir.'/'.$file)=='dir'){
loopDir($dir.'/'.$file);
}
}
}
}
$dir = '/';
loopDir($dir);
- 遍历某个目录下面的所有文件和文件夹(包含子文件夹的目录和文件也要依次读取出来)
$dir = __DIR__;
function my_dir($dir) {
$files = array();
if(@$handle = opendir($dir)) {
while(($file = readdir($handle)) !== false) {
if($file != ".." && $file != ".") {
if(is_dir($dir."/".$file)) {
$files[$file] = my_dir($dir."/".$file);
} else {
$files[] = $file;
}
}
}
closedir($handle);
return $files;
}
}
print_r(my_dir($dir));
写一个函数, 将 “open_door” 转为 “OpenDoor”
function ucstring($string){
return str_replace(' ', '', ucwords(str_replace('_', ' ', $string)));
}
# 或
function ucstring($string){
$array = explode('_', $string);
foreach($array as $key=>$val){
$new_string .= ucwords($val);
}
return $new_string;
}
写一个函数, 将 1234567890 转为 1,234,567,890 逗号隔开
function numFormate($number){
$str = (string) $number;
$string = strrev($str); # 先反转
$length = strlen($string); # 获取长度
for($i = 0; $i < $length; $i = $i+3)
{
$new_string .= substr($string, $i, 3) . ',';
}
return strrev(rtrim($new_string, ','));
}
获取扩展名
function get_ext1($file_name){
return strrchr($file_name, ‘.’);
}
function get_ext2($file_name){
return substr($file_name,strrpos($file_name, ‘.’));
}
function get_ext3($file_name){
return array_pop(explode(‘.’, $file_name));
}
function get_ext4($file_name){
$p = pathinfo($file_name);
return $p['extension'];
}
function get_ext5($file_name){
return strrev(substr(strrev($file_name), 0, strpos(strrev($file_name), ‘.’)));
}
function getExt($url){
$arr = parse_url($url);
$file = basename($arr['path']);
$ext = explode(“.”,$file);
return $ext[1];
}
求两个日期的差数, 例如2022-2-5 ~ 2022-3-6 的日期差数
function get_days($date1, $date2){
$time1 = strtotime($date1);
$time2 = strtotime($date2);
return ($time2-$time1)/86400;
}
写出一个函数,参数为年份和月份,输出结果为指定月的天数
function getDayCount($year, $month) {
$date_string = $year . '-' . $month . '-1';
return date('t', strtotime($date_string));
}
获取今天是本月所在的第几周
echo ceil(date('d')/7);