起因:因為公司遇到發稿問題,很多人喜歡用word編碼,然后再發布到網站上。PHP的包中雖然有部分可以使用的類庫,但是對于圖片始終處理不好,我就想到了python。研究了下,python將word轉為html還真是方便。但是,怎么結合到服務器上呢?我們的服務器是用PHP開發的。
1:python腳本
#!/usr/bin/python# -*- coding: UTF-8 -*-import sysfrom pydocx import PyDocXreload(sys)sys.setdefaultencoding('utf8')FileName = sys.argv[1] #獲取文件名參數ShortName = sys.argv[2] #獲取文件名參數html = PyDocX.to_html(FileName) # f = open("/www/wwwroot/micuer.com/pythoncode/runtime/99.txt", 'w') #服務器的全路徑# f.write(html)# f.close()print(html)
2:php處理腳本
public function uploadword(){ try { $file = request()->file("file"); // 上傳到本地服務器 $savename = \think\facade\Filesystem::disk('upload')->putFile( 'word', $file); $shotrname = time().".txt"; // 短名稱 $savename = "/www/wwwroot/micuer.com/data/upload/".$savename; //Request::domain(). $python_file_name = "/www/wwwroot/micuer.com/pythoncode/WordToHtml.py"; //組裝命令 $cmd = "python {$python_file_name} ".$savename." {$shotrname} 2>error.txt 2>&1"; $res = exec($cmd,$array, $ret); return json(["code"=>200,"msg"=>"成功","data"=>$savename,"cmd"=>$cmd,"array"=>$array]); } catch (think\exception\ValidateException $e) { return json(["code"=>40000,"msg"=>$e->getMessage()]); } }
上傳界面如下:
實現的功能就是利用PHP的exec函數,調用py腳本,將html代碼返回給前臺服務器。
返回數據如下
其實,再處理這個方案中,也遇到了很多問題,比如在命令行下只能成功,但是exec函數執行不成功等等。
參考了資料:https://my.oschina.net/u/4427610/blog/3155816
也就是
exec("python python_test.py 2>error.txt 2>&1", $array, $ret);
在bash中0,1,2三個數字分代表STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,即標準輸入(一般是鍵盤),標準輸出(一般是顯示屏,準確的說是用戶終端控制臺),標準錯誤(出錯信息輸出)。
也可以通過以下方式將標準錯誤重定向到標準輸出保存到$array中:
打印之后,發現是沒有權限調用。于是就直接改為輸出了,也就是 py的print(html)函數。
注意幾點:
1:執行權限問題
2:exec(“python python_test.py 2>error.txt 2>&1”, $array, $ret); 中 $array就接受到了 print(html)的值
3:各個腳本盡量使用全路徑
僅是PHP,大部分編程語言的函數或者叫方法,都可以用return來定義方法的返回值。從函數這個叫法來看,本身它就是一個計算操作,因此,計算總會有個結果,如果你在方法體中處理了結果,比如進行了持久化保存,那么這個函數就不用返回任何內容。而計算的結果是要給外部使用的,這時候就要將計算結果進行返回了。
return關鍵字
function testA($a, $b){
echo $a + $b;
}
var_dump(testA(1, 2)); // NULL
function testB($a, $b){
return $a + $b;
}
var_dump(testB(1, 2)); // 3
function testC($a, $b){
return;
echo $a + $b; // 后面不會執行了
}
var_dump(testC(1, 2)); // NULL
不用return或者直接return;都會返回NULL,return會阻斷方法體中后續代碼的執行。如果要返回多個值,只能使用數組組裝數據。
function testD($a, $b){
return [
$a + $b,
$a * $b,
];
}
var_dump(testD(1, 2)); // [3, 2]
返回值類型聲明
關于返回值這一塊還是比較好理解的。下面才是重頭戲,在PHP7的新特性中,返回值聲明是非常亮眼的一道風景。
function testE($a, $b) : bool{
if($a+$b == 3){
return TRUE;
}else{
return NULL;
}
}
var_dump(testE(1, 2)); // true
var_dump(testE(1.1, 2.2)); //TypeError: Return value of testE() must be of the type bool, null returned
如上例所示,如果返回值不是bool類型,那么將直接報TypeError的錯誤。
那么定義了返回值類型聲明有什么好處呢?我們在PHP方法參數的那點事兒有介紹過類型聲明的好處,這里就不過多贅述了,不管是參數類型聲明還是返回值類型聲明,都是一樣的。
function testF($a, $b): array{
return [
$a + $b,
$a * $b,
];
}
var_dump(testF(1, 2)); // [3, 2]
interface iA{
}
class A implements iA{}
class B extends A{
public $b = 'call me B!';
}
function testG(): A{
return new B();
}
function testH(): B{
return new B();
}
function testI(): iA{
return new B();
}
var_dump(testG()); // B的實例
var_dump(testH()); // B的實例
var_dump(testI()); // B的實例
同樣,數組和類類型都是可以聲明定義的。不過除此之外,返回值聲明還可以定義void。它的作用其實就是聲明返回值為NULL,不能直接寫:NULL,而只能用:void來進行聲明。
function testJ(): void{
echo "testJ";
// return 1;
}
var_dump(testJ());
這時,如果嘗試進行任何的return返回,都會直接報錯:Fatal error: A void function must not return a value。
總結
我們可以看到,PHP在不斷的發展中一直在吸取其他語言中的優秀特性。很明顯,添加這些類型聲明的目的就是為了將來的編譯器做準備的。這也是PHP8的一個重要特性,讓我們拭目以待吧!
測試代碼: https://github.com/zhangyue0503/dev-blog/blob/master/php/201911/source/PHP%E6%96%B9%E6%B3%95%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC.php
參考文檔: [https://www.php.net/manual/zh/functions.returning-values.php][https://www.php.net/manual/zh/functions.returning-values.php]
url是PHP的一個擴展,利用該擴展可以實現服務器之間的數據或文件傳輸。也就是說curl就是一個工具,用來做服務器之間數據、文件傳輸的工具。
用來采集網絡中的html網頁文件、其他服務器提供接口數據等
開啟curl擴展
(1) 在php.ini里面開啟curl這個擴展
(2) 將PHP的安裝路徑保存到環境變量的系統變量中(環境變量之間的分隔符是英文的分號)
(3) 重啟apache服務器
(4) 重啟計算機
curl的一些常用配置項
(1) 通過CURLOPT_RETURNTRANSFER配置項設置,是直接顯示結果(echo)還是將結果返回(return)
(2) 針對https協議的請求,需要驗證客戶端的安全證書,通常都會跳過安全證書的驗證
(3) CURLOPT_HEADER是否返回header頭信息
封裝的一個curl方法1:
<?php
/*
* 使用curl擴展發出http的get或post請求
*/
class HttpRequest
{
//url,請求的服務器地址
private $url = '';
//is_return,是否返回結果而不是直接顯示
private $is_return = 1;
public function __set($p,$v)
{
if(property_exists($this, $p)){
$this->$p = $v;
}
}
// 發出http請求的方法
//參數:提交的數據,默認是空的
public function send($data = array())
{
//1. 如果傳遞數據了,說明向服務器提交數據(post),如果沒有傳遞數據,認為從服務器讀取資源(get)
$ch = curl_init();
//2. 不管是get、post,跳過證書的驗證
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
//3. 設置請求的服務器地址
curl_setopt($ch, CURLOPT_URL, $this->url);
//4. 判斷是get還是post
if(!empty($data)){
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
//5. 是否返回數據
if($this->is_return===1){
//說明返回
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}else{
//直接輸出
curl_exec($ch);
curl_close($ch);
}
}
}
封裝的一個curl方法2:
//curl采集器
public function http_curl($url,$type='get',$res='json',$arr=''){
//1.初始化curl
$ch=curl_init();
//2.設置curl的參數
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
if($type=='post'){
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$arr);
}
//3.采集
$output=curl_exec($ch);
//4.關閉
curl_close($ch);
//如果返回的值,是json格式,則轉換成數組
if($res=='json'){
if(curl_errno($ch)){
//請求失敗,返回錯誤信息
return curl_error($ch);
}else{
//請求成功
return json_decode($output,true);
}
}
}//http_curl end
curl模擬文件上傳
說明:PHP5.6之前的版本上傳文件使用:@
Php5.6之后的版本使用new CURLFile()
這樣其他服務器接收到數據之后,就可以移動了
curl模擬cookie登錄
(1) 我們訪問服務器時,服務器會先在服務器端創建一個session文件,保存用戶的信息,便于在多個頁面共享數據,然后服務器會以setcookie的形式告訴客戶端在自己身上創建cookie,保存session文件的名,以前使用瀏覽器訪問服務器的時候,瀏覽器會在自己身上創建cookie文件,現在使用我們的服務器訪問:cookie保存到哪里?
CURLOPT_COOKIEJAR配置項設置,cookie保存到哪里
(2) 以后再訪問服務器的時候,隨身攜帶cookie(里面就是存儲的session文件的名字),那么怎么找到這個cookie呢?
CURLOPT_COOKIEFILE 配置項設置,每次請求時攜帶哪個cookie文件
PHP使用CURL詳解
CURL是一個非常強大的開源庫,支持很多協議,包括HTTP、FTP、TELNET等,我們使用它來發送HTTP請求。它給我 們帶來的好處是可以通過靈活的選項設置不同的HTTP協議參數,并且支持HTTPS。CURL可以根據URL前綴是“HTTP” 還是“HTTPS”自動選擇是否加密發送內容。
使用CURL發送請求的基本流程
使用CURL的PHP擴展完成一個HTTP請求的發送一般有以下幾個步驟:
下面的程序片段是使用CURL發送HTTP的典型過程
// 1. 初始化
$ch = curl_init();
// 2. 設置選項,包括URL
curl_setopt($ch,CURLOPT_URL,"http://www.devdo.net");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_HEADER,0);
// 3. 執行并獲取HTML文檔內容
$output = curl_exec($ch);
if($output === FALSE ){
echo "CURL Error:".curl_error($ch);
}
// 4. 釋放curl句柄
curl_close($ch);
上述代碼中使用到了四個函數
①curl_init() 和 curl_close() 分別是初始化CURL連接和關閉CURL連接,都比較簡單。
②curl_exec() 執行CURL請求,如果沒有錯誤發生,該函數的返回是對應URL返回的數據,以字符串表示滿意;如果發生錯誤,該函數返回 FALSE。需要注意的是,判斷輸出是否為FALSE用的是全等號,這是為了區分返回空串和出錯的情況。
③CURL函數庫里最重要的函數是curl_setopt(),它可以通過設定CURL函數庫定義的選項來定制HTTP請求。上述代碼片段中使用了三個重要的選項:
CURL的選項還有很多,可以到PHP的官方網站上查看CURL支持的所有選項列表。
獲取CURL請求的輸出信息
在curl_exec()函數執行之后,可以使用curl_getinfo()函數獲取CURL請求輸出的相關信息,示例代碼如下:
curl_exec($ch);
$info = curl_getinfo($sh);
echo ' 獲取 '.$info['url'].'耗時'.$info['total_time'].'秒';
上述代碼中curl_getinfo返回的是一個關聯數組,包含以下數據:
curl_getinfo()函數還有一個可選擇參數$opt,通過這個參數可以設置一些常量,對應到上述這個字段,如果設置了第二個參數,那么返回的只有指定的信息。例如設置$opt為CURLINFO_TOTAL_TIME,則curl_getinfo()函數只返回total_time,即總傳輸消耗的時間,在只需要關注某些傳輸信息時,設置$opt參數很有意義。
使用CURL發送GET請求
如何使用CURL來發送GET請求,發送GET請求的關鍵是拼裝格式正確的URL。請求地址和GET數據由一個“?”分割,然后GET變量的名稱和值用“=”分隔,各個GET名稱和值由“&”連接。PHP為我們提供了一個函數專門用來拼裝GET請求和數據部分——http_build_query,該函數接受一個關聯數組,返回由該關聯數據描述的GET請求字符串。使用這個函數,結合CURL發送HTTP請求的一般流程,我們封閉了一個發送GET請求的函數——doCurlGetRequest,具體代碼如下:
**
*@desc 封閉curl的調用接口,get的請求方式。
*/
function doCurlGetRequest($url,$data,$timeout = 5){
if($curl == "" || $timeout <= 0){
return false;
}
$url = $url.'?'.http_bulid_query($data);
$con = curl_init((string)$url);
curl_setopt($con, CURLOPT_HEADER, false);
curl_setopt($con, CURLOPT_RETURNTRANSFER,true);
curl_setopt($con, CURLOPT_TIMEOUT, (int)$timeout);
return curl_exec($con);
}
這個函數把使用http_build_query 拼裝好的帶GET參數的URL傳給curl_init函數,然后使用CURL發送HTTP請求。
使用CURL發送POST請求
可以使用CURL提供的選項CURLOPT_POSTFIELDS,設置該選項為POST字符串數據就可以把請求放在正文中。同樣我們實現了一個發送POST請求的函數——doCurlPostRequest,代碼如下:
/**
** @desc 封裝 curl 的調用接口,post的請求方式
**/
function doCurlPostRequest($url,$requestString,$timeout = 5){
if($url == '' || $requestString == '' || $timeout <=0){
return false;
}
$con = curl_init((string)$url);
curl_setopt($con, CURLOPT_HEADER, false);
curl_setopt($con, CURLOPT_POSTFIELDS, $requestString);
curl_setopt($con, CURLOPT_POST,true);
curl_setopt($con, CURLOPT_RETURNTRANSFER,true);
curl_setopt($con, CURLOPT_TIMEOUT,(int)$timeout);
return curl_exec($con);
}
上面代碼中除了設置CURLOPT_POSTFIELDS外,我們還設置了CURL_POST為true,標識這個請求是一個POST請求。在POST請求中也是可以傳輸GET數據的,只需要在URL中拼裝GET請求數據即可。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。