API 基础知识
1. url 的相关知识
1.1 一切皆”请求”
常见的请求场景如下:
- 搜索引擎查询信息
- 商城通过物流接口获取快递状态
- 微信通过支付回调 URL 通知用户支付情况
- 调用运营商接口发送短信
- 调用天气信息展示在 APP 或网站上
- 调用百度 REST API 接口实现文字转语音,实现支付语音提示
- 调用百度图片审核接口过滤非法色情图片
- 调用地图接口展示附近指定商户
- … https://www.jisuapi.com/
1.2 url 组成
任何请求都必须通过 url 发起
一个典型的 URL 格式如下:http://hostname:80/path/demo.php/a/b/c/id/5/uname/peter?k1=v1&k2=v2#anchor
-https 端口443 ftp 端口21
- http: 基于 http 协议的 url, 类似还有 https
- hostname: 接收请求的服务器 ip 地址或主机名(域名)
- 80: 端口号,如果省略则默认为 80
- path: 脚本在服务器上的路径
- index.php: 真正访问的脚本文件,实际上浏览器只关注到这个位置,后面的内容由服务器解释
- a/b/c: PATH_INFO,一种附加参数的添加方式
- ?后面的内容: k1=v1&k2=v2, 查询字符串,也是 url 附加参数,get 请求
anchor: 锚点,当前页面内跳转,可视为页面内部路由
parse_url()
函数
mvc架构的url地址pathinfo 路由映射
<?php
namespace mvc;
//mvc这种架构模式 url地址都会映射到控制器下面的一个具体操作方法上
class UserController{
public function index($id='',$name='')
{
if(!empty($id)){
return "你好 $name , 你的id是 $id";
}
return '<p>欢迎访问首页</p>';
}
public function code(){
return 'hello world!!';
}
}
// url地址:zhang.com/0518/demo.php/user/index
//var_dump($_SERVER['PATH_INFO']);
// string(11) "/user/index"
// 用/进行分割字符串
//print_r(explode("/",$_SERVER['PATH_INFO']));
/*
Array
(
[0] =>
[1] => user
[2] => index
)
*/
// 去除数组的空项,从新生成索引
$pathinfo = array_values(array_filter(explode("/",$_SERVER['PATH_INFO'])));
//print_r($pathinfo);
/*
Array
(
[0] => user
[1] => index
)
*/
$controller = array_shift($pathinfo);
// echo $controller;
// user
// echo UserController::class;
// mvc\UserController
// 将user首字母大写,在拼接上Controller
$controller = ucfirst($controller).'Controller';
// echo $controller;
// UserController
// 这样就生成了类的完全限定名称
//__NAMESPACE__空间名魔术常量
$controller = __NAMESPACE__.'\\'.$controller;
// echo $controller;
// mvc\UserController
$action = array_shift($pathinfo);
// echo (new $controller)->$action();
// echo call_user_func([new $controller,$action]);
// url地址带参数:http://zhang.com/0518/demo.php/user/index/id/6/name/zhang/email 从 url中提取参数 参数也是通过path_info方式提供
// print_r($pathinfo);
// Array ( [0] => id [1] => 6 [2] => name [3] => zhang [4] => email )
// $params = ['id'=>3,'name'=>peter];
$params = [];
for ($i=0; $i < count($pathinfo) ; $i+=2) {
if(isset($pathinfo[$i+1]) &&!empty($pathinfo[$i+1]))$params[$pathinfo[$i]] = $pathinfo[$i+1];
}
// print_r($params);
echo call_user_func_array([(new $controller),$action],$params );
?>
2. Chrome 浏览器
全球开发者使用最多的是 Chrome 浏览器,所以我们也会使用它
Chrome 开发者工具面板
- Elements: html,css…
- console: 内置的 JavaScript 调试器,可编写简单的 js 代码
- Sources: 网站中有哪些文件,图片等,可进行代码单步调试
- Network: 查看浏览器发送了哪些请求,以及响应状态
- Application: 查看 cookie,本地会话数据等
- 目前先了解以上几个面板功能即可
3. url 编码
- 百度搜索:php 中文网, 在 chrome 开发者工具 Network 中发现 php 后面的中文网变成了
%E4%B8%...
- 因为 url 仅允许数字/字母,以及部分特殊字符
!*'();:@&=+$,/?#[]
,所以中文需要进行编码 - 除了
-_.
之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号+
- 此编码与表单
POST
数据的编码方式一样 - 此编码与
enctype application/x-www-form-urlencoded
的媒体类型编码方式一样 urlencode()
和urldecode()
$url = 'https://www.baidu.com/s?wd=PHP%E4%B8%AD%E6%96%87%E7%BD%91';
echo urlencode("php中文网")."<br>"; // 编码
// php%E4%B8%AD%E6%96%87%E7%BD%91
echo urldecode("php%E4%B8%AD%E6%96%87%E7%BD%91"); // 解码
// php中文网
4. php 站点运行原理与访问流程
- 用户通过浏览器访问站点,如
php.cn
- 浏览器将用户的 http 请求发送到
php.cn
站点所在的 web 服务器 - web 服务器监听 80 端口接受请求后,发现是 php 脚本自己不能直接处理
- web 服务器如已安装 php 扩展模块,则将请求转发给 php 模块(解释器)处理
- php 根据请求,从数据库/缓存/文件中读取数据,并生成对应的 html 页面
- php 模块将生成的页面转发给 web 服务器
- web 服务器将 php 生成的 html 页面做为 http 请求的响应返回到客户端
- 客户端浏览器将收到的 html,css,js 等进行解析渲染最终生成完整页面
5. 服务器端的各个角色
5.1 web 服务器
- 主流: Apache / Nginx
- 如果是请求的是静态资源,如 html,图片等, 则直接响应即可
- 如果是动态请求(html 需要动态生成),则需要将请求转发给相应的扩展去处理
5.2 php 解释器
- 做为 web 服务器的扩展模块, 负责解析处理 php 脚本
- 生成 html 页面, 或者指定格式的字符串,如
json
5.3 数据库
- 动态网站的重要特征就是数据的动态生成
- 数据库是网站数据的最佳保存方式
- MySQL 数据库免费强大,是 PHP 的最佳拍档
5.4 缓存
- 将用户经常请求的内容, 或者更新不频繁的数据缓存起来, 可加速请求响应速度
- 当用户请求的数据已在缓存中时, 则不再进行数据库读写,而是直接从缓冲读取
- 常用缓存方式:
Redis
,Memcached
5.5 文件
- 并非所有数据都适合数据库或缓冲,例如数据库配置信息,使用文件保存更合适
- 使用文件方式,直接用 php 脚本读取,省去数据库访问的开销,效率更高更灵活
- 几乎所有框架或项目都会有一个
config
目录,就是这个原因
6. 场景介绍
- 本地环境: 本机安装全部开发组件,并通过
Git
提交供测试 - 测试环境: 通常是内网服务器,以节约成本
- 发布环境: 在创建与生产环境一致的环境, 导入真实数据线上测试
- 生产环境: 目标用户的环境,不允许再次测试,防止破坏用户数据
7. 本地环境
学习阶段, 学会搭建本地开发环境即可
- 集成环境: phpStudy_pro
- 编辑器: vscode
- [选学]版本控制系统(VCS): Gitee(码云)
7.1 phpStudy
- 下载: https://www.xp.cn/download.html
- 配置本地域名:
php.edu
- 本地项目目录:
WWW/php/
- php 版本: 7.3+
- web 服务器: Apache
vscode
- 下载: https://code.visualstudio.com/
- 常用插件列表:
Gitee学习
- 创建帐号: https://gitee.com/
- 安装 Git: https://git-scm.com/
- Git 手册: https://git-scm.com/book/zh/v2
# 初始化Git,创建本地版本库
cd php
git init
# 设置用户名和邮箱
git config --global user.name peter
git config --global user.email peter@php.cn
# 配置远程版本库
git remote add origin https://gitee.com/bnkt/php_edu.git
# 查看远程库
git remote -v
# 添加到暂存区
git add .
## 提交到本地版本库
git commit -m 'first commit'
# 查看本地状态
git status
# 提交到远程版本库
git push origin master
# 从远程仓库拉到项目到本地
git pull https://gitee.com/bnkt/php_edu.git
# 从远程仓库克隆项目到本地
git clone https://gitee.com/bnkt/php_edu.git
# 如果添加.gitignore不生效,要先清空本地缓存后再提交
git rm -r --cached .
一、URL相关函数知识点总结
1.一般URL的组成:
- 协议:http或者https等等
- 域名(ip地址)
- 端口:默认80;https默认443
- 文件路径
- 真正访问的文件
- PATH_INFO
?
查询参数:多个参数之间通过&
连接,空格用加号+
#
锚点信息
2.常见获取URL信息的函数
$_SERVER['SERVER_NAME']
获取当前脚本运行在服务的域名:主机名$_SERVER['REQUEST_URI']
URI 用来指定要访问的页面。例如
“/index.html”。$_SERVER['PHP_SELF']
获得当前执行脚本文件名:包含路径$_SERVER['SCRIPT_NAME']
包含当前脚本的路径。$_SERVER['PATH_INFO']
包含由客户端提供的、跟在真实脚本名称之后并且在查询语句(query string)之前的路径信息$_SERVER['QUERY_STRING']
获取当前请求的查询字符串
3.URL相关的函数;
urlencode("str")
与urldecode("url")
:URL地址的编码和解码parse_str("query_string",$arr);
把查询字母串解析成一个关联数组给$arr;http_build_query("关联数组");
把一个关联数组转换成查询字符串格式parse_url('url');
:解析URL并返回成一个关联数组
4.其他常用url相关的常用函数
explode("分隔符","字符串")
:把字符串分割成数组;ucfirst("字符串")
:把字符串首字母大写array_filter($arr)
:过滤数组中的空值call_user_func_array([obj,func],[参数...]);
异步调用函数__NAMESPACE__
:空间名魔术常量;
5.其他函数:
- file_exist(“文件路径名字”):判断文件是否存在
- file_put_contents(“文件名”,”写入内容”,FILE_APPEND);把内容追加写入文件
PHP_EOL
:换行常量
本地日志方式存储请求的数据
<?php
// $in_res = json_decode(file_get_contents("https://tianqiapi.com/api?version=epidemic&appid=69872991&appsecret=9PHfhTUt"),true);
// print_r($in_res) ;
// $ex_res = json_decode(file_get_contents("http://api.tianapi.com/txapi/ncovabroad/index?key=6c6d319a9f3b53c53b375c56fbd39207"),true);
// echo '<pre>'.print_r($ex_res,true).'</pre>' ;
// https://www.php.cn/course/1172.html
$data = '时间:' . date('Y-m-d H:i:s',time()).PHP_EOL;
// $_REQUEST可以获取到$_POST $_GET $_COOKIE
$data.= '请求数据' . json_encode($_REQUEST) . PHP_EOL;
if(file_put_contents('log.txt',$data,FILE_APPEND)) exit('写入成功');
二、PHP发起http请求:curl函数的使用
使用CURL的PHP扩展完成一个HTTP请求的发送一般有以下几个步骤:
- 初始化连接句柄;
初始化请求会话:$curl=curl_init();
- 设置CURL选项;
curl_setopt($curl,CURLOPT_URL,"http://www.devdo.net");
curl_setopt($curlh,CURLOPT_RETURNTRANSFER,1);
curl_setopt($curl,CURLOPT_HEADER,0);
url_setopt($curl,”参数类型常量”,参数值);设置请求会话配置项;参数类型常量如下
- CURLOPT_URL:请求url
- CURLOPT_HTTPGET:设置请求类型GET;值为true|flase;
- CURLOPT_HEADER:设置请求头信息:flase;
- CURLOPT_RETURNTRANSFER:设置指只返回结果,不输出;true;
- 执行并获取结果;
执行请求返回结果$res=curl_exec($curl);
- 释放VURL连接句柄。
关闭请求会话;curl_close($curl);
//模拟发送GET请求(使用curl)
function httpGet($url,$data){
$curl=curl_init();
curl_setopt($curl,CURLOPT_URL,$url.$data);
curl_setopt($curl,CURLOPT_HTTPGET,true);
curl_setopt($curl,CURLOPT_HEADER,false);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
return $res=curl_exec($curl);
curl_close($curl);
}
//模拟发送POST请求(使用curl)
function httpPost($url,$data){
//1.创建curl句柄
$curl = curl_init();
//2.设置curl
curl_setopt($curl,CURLOPT_URL,$url);
//3.捕获内容但不输出
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
//4.模拟发送POST请求
curl_setopt($curl,CURLOPT_POST,1);
//5.模拟POST请求值传递数据
curl_setopt($curl,CURLOPT_POSTFIELDS,$data);
//6.禁止服务器端校验SSL
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
//7.执行curl
$result = curl_exec($curl);
//8.关闭curl
curl_close($curl);
//9.返回请求的结果
return $result;
}
三、请求第三方接口案例实战:
<?php
$url="http://v.juhe.cn/joke/content/text.php?";
$key="b82ad6748770b5130d49f61a7e12bae0";
$page=1;
$pagesize=8;
$time=time();
// 生成url-encode之后的请求字符串
$query=http_build_query(["key"=>$key,"page"=>$page,"pagesize"=>$pagesize]);
// echo "<pre>".$url.$query;
// http://v.juhe.cn/joke/content/text.php?key=b82ad6748770b5130d49f61a7e12bae0&page=1&pagesize=8
//模拟发送GET请求(使用curl)
function httpGet($url,$data){
$curl=curl_init();
curl_setopt($curl,CURLOPT_URL,$url.$data);
curl_setopt($curl,CURLOPT_HTTPGET,true);
curl_setopt($curl,CURLOPT_HEADER,false);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
return $res=curl_exec($curl);
curl_close($curl);
}
$res = httpGet($url,$query);
// var_dump($curl);
$data=json_decode($res,true);//把json数据类型转换成数组
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>api-5个小笑话</title>
</head>
<body style="width: 800px;margin: 0 auto;">
<?php if($data["error_code"]===0):?>
<?php foreach($data["result"]["data"] as $row):?>
<h3><?= $row["updatetime"]?></h3>
<p><?= $row["content"]?></p>
<hr>
<?php endforeach ?>
<?php else:?>
<p><?=$data["reason"]?></p>
<?php endif ?>
</body>
</html>
<?php
// phpinfo();
//curl 初始化 获取一个curl句柄 发起http请求
$url = "http://apis.juhe.cn/simpleWeather/query?";
$key = "0f590369d3d3c9f902282fcc886b8ad1";
$city = "合肥";
$query = http_build_query(["key"=>'0f590369d3d3c9f902282fcc886b8ad1','city'=>'合肥']);
// echo $url.$query;
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url.$query);
curl_setopt($ch,CURLOPT_HTTPGET,true);
curl_setopt($ch,CURLOPT_HEADER,false);
// 默认是浏览器输出,只返回不输出
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$apiData = curl_exec($ch);
// echo $apiData;
curl_close($ch);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
table {
color: #555;
background-color: #efefef;
border-collapse: collapse;
width: 600px;
text-align: center;
margin: auto;
}
td {
border: 2px solid #FFF;
padding: 5px;
}
table caption {
font-size: 1.2rem;
margin-bottom: 15px;
}
table thead tr:first-of-type {
background-color: darkturquoise;
color: white;
}
</style>
<body>
<script>
const obj = <?=$apiData?>;
console.log(obj);
console.log(obj.result.city);
// 创建表格元素
const table = document.createElement('table');
console.log(table);
// 表头: 城市 + 标题, 如:合肥天气预报
table.createCaption().textContent = obj.result.city + ' 天气预报';
// 创建表头,并尾部添加新行,将表头参数填入
const tr = table.createTHead().insertRow(-1);
tr.insertCell(0).innerText = '日期';
tr.insertCell(1).innerText = '气温';
tr.insertCell(2).innerText = '雨雪';
tr.insertCell(3).innerText = '风向';
// 遍历未来几天的天气对象数组
obj.result.future.forEach(item=>{
// 先生成一个新行,并插入到表尾
const row = table.insertRow(-1);
// [选学] 转日期格式
let date = new Date(Date.parse(item.date.replace(/-/g, '/')));
// 组装成符合国人阅读习惯的格式
let timeStr = `${date.getFullYear()}年${date.getMonth()+1}月${date.getDate()}日`;
// console.log(timeStr);
// console.log(date);
// 遍历每一天的天气对象数组,并填充到生成的单元格中
row.insertCell(0).innerText = timeStr;
// row.insertCell(0).innerText = item.date;
row.insertCell(1).innerText = item.temperature;
row.insertCell(2).innerText = item.weather;
row.insertCell(3).innerText = item.direct;
// 将生成的该行插入到表格元素中
table.appendChild(row);
});
// 最后将表格添加到页面中
document.body.appendChild(table);
</script>
</body>
</html>
<?php
function httpGet($url,$data){
$curl=curl_init();
curl_setopt($curl,CURLOPT_URL,$url.$data);
curl_setopt($curl,CURLOPT_HTTPGET,true);
curl_setopt($curl,CURLOPT_HEADER,false);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
return $res=curl_exec($curl);
curl_close($curl);
}
$key = 'd9aab3d5e99d7e7f3eb0ba26f4f969a0';
$subset = "1";
$model= "c1";
$testType="rand";
$url = "http://v.juhe.cn/jztk/query?";
$query = http_build_query(["subject"=>$subset,'model'=>$model,"testType"=>$testType,"key"=>$key]);
$res = httpGet($url,$query);
$answers = httpGet("http://v.juhe.cn/jztk/answers?",http_build_query(["key"=>$key]));
?>
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://unpkg.com/art-template@4.13.2/lib/template-web.js"></script>
<style type="text/css">
#container{
width: 900px;
margin: 0 auto;
}
ul li{
list-style: none;
margin-bottom: 62px;
border: 1px solid #eee;
padding: 18px;
box-shadow: 3px 3px 24px #ddd;
}
.answers{
color: white;
padding: 6px;
background: #d81414;
margin: 6px;
display: inline-block;
border-radius: 8px;
}
.explains{
width: 80%;
border: 2px dotted red;
padding: 8px;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/html" id="template">
<h1 align="center">驾考题库</h1>
<ul>
{{if result}}
{{each result value index}}
<li>
<h3 class="title">第{{value.id}}题:{{value.question}}</h3>
<img src="{{value.url}}">
<p class="item">
<span>A、{{value.item1}}</span>
<span>B、{{value.item2}}</span>
{{if value.item3}}
<span>C、{{value.item3}}</span>
{{/if}}
{{if value.item4}}
<span>C、{{value.item4}}</span>
{{/if}}
</p>
<span class="answers">答案:{{answers.result[value.answer]}}</span>
<div class="explains">解析:{{value.explains}}</div>
</li>
{{/each}}
{{/if}}
</ul>
</script>
<script>
const data = <?=$res ?>;
data.answers = JSON.parse('<?=$answers?>');
const html = template('template',data);
document.querySelector('#container').innerHTML = html;
</script>
</body>
</html>
请求第三方接口天气预报官方示例
<?php
// 请求的接口URL
$apiUrl = 'http://apis.juhe.cn/simpleWeather/query';
// 请求参数
$params = [
'city' => '苏州', // 要查询的城市
'key' => '0f590369d3d3c9f902282fcc886b8ad1'
];
$paramsString = http_build_query($params);
// 发起接口网络请求
$response = juheHttpRequest($apiUrl, $paramsString , 1);
$result = json_decode($response, true);
if ($result) {
$errorCode = $result['error_code'];
if ($errorCode == 0) {
// 获取返回的天气相关信息,具体根据业务实际逻辑调整修改
$data = $result['result'];
// 打印当前实况天气信息
echo "当前城市:{$data["city"]}".PHP_EOL;
echo "当前温度:{$data["realtime"]["temperature"]}".PHP_EOL;
echo "当前湿度:{$data["realtime"]["humidity"]}".PHP_EOL;
echo "当前天气:{$data["realtime"]["info"]}".PHP_EOL;
echo "当前风向:{$data["realtime"]["direct"]}".PHP_EOL;
echo "当前风力:{$data["realtime"]["power"]}".PHP_EOL;
echo "当前空气质量:{$data["realtime"]["aqi"]}".PHP_EOL;
} else {
// 请求异常
echo "请求异常:{$errorCode}_{$result["reason"]}".PHP_EOL;
}
} else {
// 可能网络异常等问题,无法正常获得相应内容,业务逻辑可自行修改
echo "请求异常".PHP_EOL;
}
/**
* 发起网络请求函数
* @param $url 请求的URL
* @param bool $params 请求的参数内容
* @param int $ispost 是否POST请求
* @return bool|string 返回内容
*/
function juheHttpRequest($url, $params = false, $ispost = 0)
{
$httpInfo = array();
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 12);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if ($ispost) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_URL, $url);
} else {
if ($params) {
curl_setopt($ch, CURLOPT_URL, $url.'?'.$params);
} else {
curl_setopt($ch, CURLOPT_URL, $url);
}
}
$response = curl_exec($ch);
if ($response === FALSE) {
// echo "cURL Error: ".curl_error($ch);
return false;
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$httpInfo = array_merge($httpInfo, curl_getinfo($ch));
curl_close($ch);
return $response;
}
PHP通用请求函数,CURL封装 curl.func.php
<?php
/**
* 使用:
* echo curlOpen('https://www.baidu.com');
*
* POST数据
* $post = array('aa'=>'ddd','ee'=>'d')
* 或
* $post = 'aa=ddd&ee=d';
* echo curlOpen('https://www.baidu.com',array('post'=>$post));
* @param string $url
* @param array $config
*/
function curlOpen($url, $config = array())
{
$arr = array('post' => false,'referer' => $url,'cookie' => '', 'useragent' => 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; customie8)', 'timeout' => 20, 'return' => true, 'proxy' => '', 'userpwd' => '', 'nobody' => false,'header'=>array(),'gzip'=>true,'ssl'=>false,'isupfile'=>false);
$arr = array_merge($arr, $config);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, $arr['return']);
curl_setopt($ch, CURLOPT_NOBODY, $arr['nobody']);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_USERAGENT, $arr['useragent']);
curl_setopt($ch, CURLOPT_REFERER, $arr['referer']);
curl_setopt($ch, CURLOPT_TIMEOUT, $arr['timeout']);
//curl_setopt($ch, CURLOPT_HEADER, true);//获取header
if($arr['gzip']) curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
if($arr['ssl'])
{
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
}
if(!empty($arr['cookie']))
{
curl_setopt($ch, CURLOPT_COOKIEJAR, $arr['cookie']);
curl_setopt($ch, CURLOPT_COOKIEFILE, $arr['cookie']);
}
if(!empty($arr['proxy']))
{
//curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
curl_setopt ($ch, CURLOPT_PROXY, $arr['proxy']);
if(!empty($arr['userpwd']))
{
curl_setopt($ch,CURLOPT_PROXYUSERPWD,$arr['userpwd']);
}
}
//ip比较特殊,用键值表示
if(!empty($arr['header']['ip']))
{
array_push($arr['header'],'X-FORWARDED-FOR:'.$arr['header']['ip'],'CLIENT-IP:'.$arr['header']['ip']);
unset($arr['header']['ip']);
}
$arr['header'] = array_filter($arr['header']);
if(!empty($arr['header']))
{
curl_setopt($ch, CURLOPT_HTTPHEADER, $arr['header']);
}
if ($arr['post'] != false)
{
curl_setopt($ch, CURLOPT_POST, true);
if(is_array($arr['post']) && $arr['isupfile'] === false)
{
$post = http_build_query($arr['post']);
}
else
{
$post = $arr['post'];
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
}
$result = curl_exec($ch);
//var_dump(curl_getinfo($ch));
curl_close($ch);
return $result;
}
请求示例:
<?php
require_once 'curl.func.php';
$appkey = 'your_appkey_here';//你的appkey
$url = "https://api.jisuapi.com/tangshi/chapter?appkey=$appkey";
$result = curlOpen($url, ['ssl'=>true]);
$jsonarr = json_decode($result, true);
//exit(var_dump($jsonarr));
if($jsonarr['status'] != 0)
{
echo $jsonarr['msg'];
exit();
}
$result = $jsonarr['result'];
foreach($result as $val)
{
echo $val['detailid'].' '.$val['name'].' '.$val['author'].'<br>';
}
Composer的安装与基本使用
一、Composer下载安装
Composer 是 PHP 用来管理依赖(dependency)关系的工具。你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer 会帮你安装这些依赖的库文件,有了它,我们就可以很轻松的使用一个命令将其他人的优秀代码引用到我们的项目中来。Composer 默认情况下不是全局安装,而是基于指定的项目的某个目录中(例如 vendor)进行安装。Composer 需要 PHP 5.3.2+ 以上版本,且需要开启 openssl。Composer 可运行在 Windows 、 Linux 以及 OSX 平台上。
1、下载Composer
composer安装请参考:https://pkg.phpcomposer.com/#how-to-install-composer
composer官网下载地址:https://getcomposer.org/composer.phar
2、安装Composer
1)、Composer安装前请确保已经安装了php;打开命令行窗口输入php -v可以查看php的当前版本号。并确保将 php.exe 所在路径添加到全局 path 环境变量中。
局部安装与全局安装
局部安装:正确安装完后,可以将 composer.phar
文件复制到任意目录(比如项目根目录下),然后通过 php composer.phar
指令即可使用 Composer 了
全局安装:将 Composer 安装到系统环境变量 PATH
所包含的路径下面,然后就能够在命令行窗口中直接执行 composer
命令了
- 将下载的 composer.phar 复制到 php.exe 所在目录中
- 创建 composer.bat:
@php "%~dp0composer.phar" %*
- 命令 php composer.phar -V 可以简写为 composer -V
注:composer —version命令可以查看版本信息;如果全局查找不到,可以将D:\phpstudy_pro\Extensions\composer1.8.5也添加到环境变量中去。
3、更新composer
Composer 升级时是无法利用我们的镜像加速下载的,而必须连接到 Composer 国外官网的服务器上下载升级文件,某些时候就会导致升级的速度非常慢甚至失败。
这里提供一个简单的办法:
如果你的系统中已经有可以正常使用的 Composer 了,说明系统环境是符合要求的,那么只需要下载新的 Composer 文件并覆盖原来的文件即可。
首先你要确定现有的 Composer 的安装目录,然后通过下面的链接下载 composer.phar
文件(复制以下地址到浏览器地址栏可直接下载),
https://install.phpcomposer.com/composer.phar
将前面下载的 composer.phar
文件覆盖系统中已经安装的 composer.phar
文件即可。注意,有可能在安装时将 composer.phar
改名为 composer
了,注意用同样的名字覆盖即可。
二、Composer切换镜像
一般情况下,安装包的数据(主要是 zip 文件)一般是从 github.com
上下载的,安装包的元数据是从 packagist.org
上下载的。
然而,由于众所周知的原因,国外的网站连接速度很慢,并且随时可能被“墙”甚至“不存在”。
“Packagist 中国全量镜像”所做的就是缓存所有安装包和元数据到国内的机房并通过国内的 CDN 进行加速,这样就不必再去向国外的网站发起请求,从而达到加速 composer install
以及 composer update
的过程,并且更加快速、稳定。因此,即使 packagist.org
、github.com
发生故障(主要是连接速度太慢和被墙),你仍然可以下载、更新安装包。
Packagist 镜像使用方法:https://pkg.phpcomposer.com/#how-to-use-packagist-mirror
composer切换镜像:
- composer中文网:
composer config repo.packagist composer https://packagist.phpcomposer.com
- composer阿里云:
composer config repo.packagist composer https://mirrors.aliyun.com/composer/
packagist(包依赖网站):https://packagist.org/
// 切换镜像源
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
// 取消配置
composer config -g --unset repos.packagist
// 只针对当前项目切换镜像源(非全局切换)
composer config repo.packagist composer https://mirrors.aliyun.com/composer/
// 取消当前项目的镜像源
composer config --unset repos.packagist
三、Composer基本使用
composer常见组成文件
- composer.json : composer组件基本配置信息和包依赖以及autoload
- composer.lock : 锁定包依赖的版本号
- vendor :包的源代码和包依赖的文件
使用composer安装thinkPHP框架
composer create-project topthink/think ./
1、composer update、composer install 与 composer require的区别
Composer update:
根据composer.json文件的包依赖关系将包更新到最新版本,并将版本依赖信息更新到composer.lock文件中;
Composer update vendor/package:
从composer.json获取依赖关系,并将指定的package更新到最新版本,并将版本信息更新到composer.lock文件;
Composer install:
若有composer.lock文件,则据此直接安装,否则就根据composer.json文件安装最新扩展包和依赖;
Composer require package(new):
项目有新的扩展包和依赖时,通过此命令添加,可以指定版本,例如:composer require package ~2.5;**
注意:composer update 命令会将所有包和依赖更新到最新版本,可能会对项目产生巨大伤害,需要慎用!!!
2、composer.json与composer.lock的区别
composer.json:
此文件用来声明项目中包之间的依赖关系以及一些元素信息;
composer.lock:
此文件用来锁定项目中包与依赖的版本信息,通常配合composer install来使用,确保项目中的成员得到一个版本的包与依赖关系;
四、Composer常用命令
- composer init : 交互式创建composer.json
- composer install: 安装 composer.json 中的依赖
- composer update :忽略.lock文件锁定,更新包依赖到最新版本
- composer selfupdate :更新composer至最新版本
- composer require :添加依赖到 composer.json 中
- composer create-porject : 创建安装项目
- composer config -l -g 查看composer配置
- composer dump :更新json文件的autoload配至项
composer show : 查看所有已经安装的包的信息
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
五、Composer自动加载
自动加载配置:autoload;在json配置文件中”autoload”字段中的配置方式
- 文件级“files”:[];把需要自动加载的文件写入数组中即可
- 目录级“classmap”:[]把需要加载文件的目录写入数组中即可
- 空间级“psr-4”:[]把需要自动加载的类的命名空间映射到目录,以键值的方式写入数组中
- 最后要执行一下”composer dump”,更新 composer.json 中的 autoload 配置项
1.composer.json:项目设置
若要在项目中使用 Composer 你需要一个 composer.json 文件。该文件描述了你的项目依赖关系和其他元数据。把相关的项目包含进入到composer
首先(通常也是唯一)应该做的事情就是在你的 composer.json 文件中定义好 require 键。你应该简要告诉 Composer 你的项目所依赖的包有哪些。
当我们的composer.json文件中增加了项目的依赖关系,如下:
{
"require":{
"topthink/framework": "5.0.5",
"monolog/monolog":"1.0.*"
}
}
如上所示, require 获取了一个包名称 (例如 monolog/monolog)映射到版本约束 (例如 1.0.*)的 json 对象。
此时我们使用 composer install时,会自动根据包中的依赖关系,来安装相对应的包。
composer 使用该信息去「版本库」中搜索,你在 Composer.json 中注册的 repositories 键所指定的版本仓库中的相关合适的文件,或是在 Packagist 中默认的包库。在上述示例中,因为没有其他在 composer.json 文件中注册的版本库信息,所以它认为 monolog/monolog 包默认是在 Packagist 中。
2. 在控制台命令行下面进入到 composer.json 的目录下面去
进行如下的命令 composer install
这样会在 你的venrdor 文件下面生产一个依赖包的文件
3.composer.lock 锁文件
我们在使用composer的过程中会发现,当我们执行composer update等命令,会发现无意中多了一个composer.lock文件。那这个文件主要是干什么的呢?该文件主要是管理包版本使用的,当我们在使用composer update命令时,composer会自动根据composer.json的包版本依赖,生成对应的composer.lock文件,当我们下次在执行composer命令的时候,首先也会去读取composer.lock文件的内容。
每次在你安装好依赖后都会生成一个composer.json 的锁文件 这样在你下次install 的时候会先检查你的锁文件里面的东西而忽视你的composer.json 里面的东西
如果你要更新你的依赖则使用 composer update
该命令会根据composer.json配置文件中包依赖以及相应的版本,更新包的版本,但是该命令会将所有的包都更新到最新版本,在实际的项目中需要谨慎使用,尤其是在生产环境上面。
4.Packagist
大部分依赖包都可以在此找到 https://packagist.org/
5.自动加载
为了描述包的自动加载信息, Composer 会生成一个 vendor/autoload.php 文件,你可以简单的 include 这个文件,并在无需其它额外工作的情况下就可以使用这些包所提供的类:
在你的项目中加入这段引入文件
require __DIR__ . '/vendor/autoload.php';
$log = new Monolog\Logger('name');
$log->pushHandler(new Monolog\Handler\StreamHandler('app.log', Monolog\Logger::WARNING));
$log->addWarning('Foo');
你甚至可以在 composer.json 中添加一个 autoload 指令,来添加自己的自动加载声明
{
"autoload": {
"psr-4": {"Acme\\": "src/"}
}
}
Composer 会为 Acme 命名空间注册一个 PSR-4 的自动加载.
你定义一个命名空间指向目录的映射。 在 vendor 目录同级的 src 目录将成为你项目的根目录。一个案例,文件名 src/Foo.php 需包含 AcmeFoo 类。
添加 autoload 指令之后,你必需重新运行 dump-autoload 来重新生成 vendor/autoload.php 文件。
Composer版本约束
在我们使用composer安装包时,不得不考虑的就是一个版本问题,因为不同的版本,存在兼容性问题,因此我们在使用该工具安装包时需要特别的注意包版本,如果使用不当很容易导致项目因为包版本问题瘫痪。常见的几种如下:
1.精准版本
明确要安装到那个版本,如需要安装包的版本是1.2.3
"topthink/think-captcha": "v1.2.3",
2.通配符
既满足指定范围即可,如下范围在5.0到5.1之间
"topthink/framework": "5.0.*",
3.范围
范围常用的操作符有>,>=,<,<=,!=。你可以定义多个范围,使用空格或者逗号 , 表示逻辑上的与,使用双竖线 || 表示逻辑上的或。其中与的优先级会大于或。
// 表示大于等于0.90并且小于3.0的版本"ruflin/elastica": ">=0.90 <3.0",
4.波浪符 ~
该操作符限制最小版本号。
允许表达式中的最后一位版本号达到最大值
如~1.2与>=1.2 <2.0相等,~1.5.6与>=1.5.6 < 1.6.0相等。也就是主版本号与次版本号保持不变,修复版本号可以达到最大值。
5.折音符 ^
该操作符约束锁定最大版本号。
锁定表达不变的是第一位主版本号,允许升级版本到安全的版本号
如^1.2就等于>=1.2 <2.0,^1.2.3就等于>=1.2.3 < 2.0.0。