1. 程式人生 > 實用技巧 >PHP檔案上傳、錯誤處理

PHP檔案上傳、錯誤處理

說明

這篇是針對之前php知識的補充內容

目錄

1、 PHP目錄處理函式

處理資料夾的基本思想如下:
1.讀取某個路徑的時候判斷是否是資料夾
2.是資料夾的話,開啟指定資料夾,返回檔案目錄的資源變數
3.使用readdir讀取一次目錄中的檔案,目錄指標向後偏移一次
4.使用readdir讀取到最後,沒有可讀的檔案返回false
5.關閉檔案目錄

我們來學習一比常用函式:

函式名 功能
opendir 開啟資料夾,返回操作資源
readdir 讀取資料夾資源
is_dir 判斷是否是資料夾
closedir 關閉資料夾操作資源
filetype 顯示是資料夾還是檔案,檔案顯示file,資料夾顯示dir
<?php
//設定開啟的目錄是D盤
$dir = "d:/";

//判斷是否是資料夾,是資料夾
if (is_dir($dir)) {
   if ($dh = opendir($dir)) {


      //讀取到最後返回false,停止迴圈
      while (($file = readdir($dh)) !== false) {
           echo "檔名為: $file : 檔案的型別是: " . filetype($dir . $file) . "<br />";
       }

       closedir($dh);
   }
}
?>

2、 PHP檔案許可權設定

chmod 主要是修改檔案的的許可權

<?php
//修改linux  系統/var/wwwroot/某檔案許可權為755
chmod("/var/wwwroot/index.html", 755);  
chmod("/var/wwwroot/index.html", "u+rwx,go+rx"); 
chmod("/somedir/somefile", 0755); 
?>

3、 PHP檔案路徑函式

我們經常會遇到處理檔案路徑的情況。
例如:
1.檔案字尾需要取出來
2.路徑需要取出名字不取目錄
3.只需要取出路徑名中的目錄路徑
4.或者把網址中的各個部份進行解析取得獨立值
5.甚至是自己組成一個url出來
... ....

很多地方都需要用路徑處理類的函式。

我們把常用的路徑處理函式為大家做了標註,大家對著這個路徑處理函式進行處理即可:

函式名 功能
pathinfo 返回檔案的各個組成部份
basename 返回檔名
dirname 檔案目錄部份
parse_url 網址拆解成各部份
http_build_query 生成url 中的query字串
http_build_url 生成一個url
<?php
$path_parts = pathinfo('d:/www/index.inc.php');

echo '檔案目錄名:'.$path_parts['dirname']."<br />";
echo '檔案全名:'.$path_parts['basename']."<br />";
echo '副檔名:'.$path_parts['extension']."<br />";
echo '不包含擴充套件的檔名:'.$path_parts['filename']."<br />"; 
?>

4、 PHP實現檔案留言本

我們來看一下檔案結構:
index.php ---展示輸入框和留言內容
write.php ---向message.txt寫入資料
message.txt ---存入聊天內容
index.php檔案

<?Php
//設定時區
date_default_timezone_set('PRC');
//讀了內容
@$string = file_get_contents('message.txt');
//如果$string 不為空的時候執行,也就是message.txt中有留言資料
if (!empty($string)) {
    //每一段留言有一個分格符,但是最後多出了一個&^。因此,我們要將&^刪掉
    $string = rtrim($string, '&^');
    //以&^切成陣列
    $arr = explode('&^', $string);
    //將留言內容讀取
    foreach ($arr as $value) {
        //將使用者名稱和內容分開
        list($username, $content, $time) = explode('$#', $value);
        echo '使用者名稱為<font color="gree">' . $username . '</font>內容為<font color="red">' . $content . '</font>時間為' . date('Y-m-d H:i:s', $time);
        echo '<hr />';
    }
}
?>
<h1>基於檔案的留言本演示</h1>
<form action="write.php" method="post">
    使用者名稱:<input type="text" name="username" /><br />
    留言內容:<textarea  name="content"></textarea><br />
    <input type="submit" value="提交" />
</form>

看了剛剛的展示內容,我們知道檔案儲存時:
1.段與段之間進行了分割
2.內容與使用者之前用一個特殊的符號進行了分割

下面我們來寫write.php寫入留言至檔案的程式碼:

<?php
//追加方式開啟檔案
$fp=fopen('message.txt','a');

//設定時間
$time=time();

//得到使用者名稱
$username=trim($_POST['username']);
//得到內容
$content=trim($_POST['content']);


//組合寫入的字串:內容和使用者之間分開,使用$#
//行與行之間分開,使用&^
$string=$username.'$#'.$content.'$#'.$time.'&^';

//寫入檔案
fwrite($fp,$string);

//關閉檔案
fclose($fp);


header('location:index.php');

?>

5、PHP檔案上傳

在我們日常使用中經常會遇到很多種這樣的情況:
QQ空間裡面上傳圖片呀
微信朋友圈上傳圖片
發郵件裡面上傳郵件資料附件
認證的時候要求上傳照片或身份證

檔案上傳需要注意php.ini檔案

配置項 功能說明
file_uploads on為 開啟檔案上傳功能,off為關閉
post_max_size 系統允許的POST傳參的最大值
upload_max_filesize 系統允許的上傳檔案的最大值
memory_limit 記憶體使用限制

建議尺寸: file_size(檔案大小) < upload_max_filesize < post_max_size < memory_limit
另外,需要注意的是指令碼執行時間。
max_execution_time,這什引數的單位為秒。
這個引數是設定指令碼的最大執行時間。
也可以根據需求做適當的改變。通常不需要來修改,系統預設值即可。超大檔案上傳的時候,可能會涉及到這一項引數的修改。
上傳時間太長了,會超時。如果你將此項引數設為0,則是不限制超時時間,不建議使。
完成了php.ini的相關配置,我們就可以開始試著完成第一次檔案上傳了。

1. php檔案上傳的步驟

系統返回的錯誤碼詳解

錯誤碼 說明
0 無誤,可以繼續進行檔案上傳的後續操作。
1 超出上傳檔案的最大限制,upload_max_filesize = 2M php.ini中設定,一般預設為2M。可根據專案中的實際需要來修改
2 超出了指定的檔案大小,根據專案的業務需求指定上傳檔案的大小限制
3 只有部分檔案被上傳
4 檔案沒有被上傳
6 找不到臨時資料夾,可能目錄不存在或沒許可權
7 檔案寫入失敗,可能磁碟滿了或沒有許可權

注:錯誤碼中沒有5。

2. 自定義判斷是否超出檔案大小範圍

在開發上傳功能時。我們作為開發人員,除了php.ini中規定的上傳的最大值外。 我們通常還會設定一個值,是業務規定的上傳大小限制。
例如:
新浪微博或者QQ空間只准單張頭像圖片2M。而在上傳圖冊的時候又可以超過2M來上傳。
所以說,它的系統是支援更大檔案上傳的。
此處的判斷檔案大小,我們用於限制實際業務中我們想要規定的上傳的檔案大小。

3. 判斷後綴名和mime型別是否符合

在網路世界裡面也有壞人。他們會把圖片插入病毒,在附件中上傳病毒,他們會在網頁中插入病毒或者黃色圖片。
我們需要對於上傳的檔案字尾和mime型別都要進行判斷才可以。
MIME(Multipurpose Internet Mail Extensions)是多用途網際網路郵件擴充套件型別。是設定某種副檔名的檔案用一種應用程式來開啟的方式型別,當該副檔名檔案被訪問的時候,瀏覽器會自動使用指定應用程式來開啟。多用於指定一些客戶端自定義的檔名,以及一些媒體檔案開啟方式。
在判斷後綴和MIME型別的時候,我們會用到PHP的一個函式in_array(),該函式傳入兩個引數。
第一個引數是要判斷的值;
第二個引數是範圍陣列。
我們用這個函式來判斷檔案的字尾名和mime型別是否在允許的範圍內。

4. 生成檔名

我們的檔案上傳成功了,不會讓它儲存原名。因為,有些人在原名中有敏感關鍵詞會違反我國的相關法律和法規。我們可以採用date()、mt_rand()或者unique()生成隨機的檔名。

5. 判斷是否是上傳檔案

檔案上傳成功時,系統會將上傳的臨時檔案上傳到系統的臨時目錄中。產生一個臨時檔案。同時會產生臨時檔名。我們需要做的事情是將臨時檔案移動到系統的指定目錄中。
而移動前不能瞎移動,或者移動錯了都是不科學的。移動前我們需要使用相關函式判斷上傳的檔案是不是臨時檔案。
is_uploaded_file()傳入一個引數($_FILES中的快取檔名),判斷傳入的名稱是不是上傳檔案。

6. 移動臨時檔案到指定位置

臨時檔案是真實的臨時檔案,我們需要將其移動到我們的網站目錄下面了。
讓我們網站目錄的資料,其他人可以訪問到。
我們使用:move_uploaded_file()。
這個函式是將上傳檔案移動到指定位置,並命名。
傳入兩個引數:
第一個引數是指定移動的上傳檔案;
第二個引數是指定的資料夾和名稱拼接的字串。

7. php檔案上傳表單注意事項

**程式碼如下:

1.index.html**

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>無標題文件</title>
</head>
<body>
<h1>上傳檔案</h1>
<form action="chuli.php" method="post" enctype="multipart/form-data">
請選擇檔案:<input type="file" name="file" /><input type="submit" value="上傳" />
</form>
</body>
</html>

注意事項:
1.form 表單中的引數method 必須為post。若為get是無法進行檔案上傳的
2.enctype須為multipart/form-data

2.chuli.php

<?php
//取檔案資訊
$arr = $_FILES["file"];
//var_dump($arr);
//加限制條件
//1.檔案型別
//2.檔案大小
//3.儲存的檔名不重複
if(($arr["type"]=="image/jpeg" || $arr["type"]=="image/png" ) && $arr["size"]<10241000 )
{
//臨時檔案的路徑
$arr["tmp_name"];
//上傳的檔案存放的位置
//避免檔案重複: 
//1.加時間戳.time()加使用者名稱.$uid或者加.date('YmdHis')
//2.類似網盤,使用資料夾來防止重複
$filename = "./images/".date('YmdHis').$arr["name"];
//儲存之前判斷該檔案是否存在
  if(file_exists($filename))
  {
    echo "該檔案已存在";
  }
  else
  {
  //中文名的檔案出現問題,所以需要轉換編碼格式
  $filename = iconv("UTF-8","gb2312",$filename);
  //移動臨時檔案到上傳的檔案存放的位置(核心程式碼)
  //括號裡:1.臨時檔案的路徑, 2.存放的路徑
  move_uploaded_file($arr["tmp_name"],$filename);
  echo "檔案上傳成功";
  }
}
else
{
  echo "上傳的檔案大小或型別不符";
}
?>

6、 PHP錯誤處理

在php.ini配置檔案中。我們可以控制php的錯誤顯示狀態。php.ini中有一個專門的配置項:
display_errors
這個選項設定是否將錯誤資訊輸出到網頁,或者對使用者隱藏而不顯示。
這個值的狀態為on 或者 off,也可以設值為1 或者0。
display_error的值設為0或者off則不在頁面中顯示錯誤,如果設為1或者on則顯示錯誤資訊。

問題:如果沒有修改伺服器php.ini的狀態許可權怎麼辦?
可以使用ini_set。
<?php
ini_set('display_errors' , 0 );
?>
上面的程式碼也相當於修改了php.ini中display_errors的值。不過,僅僅在當前php程式碼中生效。

問題:想取得php.ini的配置項狀態怎麼辦?
可以使用ini_get(引數項) 得到引數的值。

<?php
echo '伺服器中display_errors的狀態為' . ini_get('display_errors');
?>

注:修改完php.ini檔案,需要重啟伺服器

1. php錯誤處理之錯誤報告級別

【掌握級別的錯誤型別】 我們將最常用的錯誤分為了三種:

錯誤型別 說明
E_ERROR 錯誤,檔案直接中斷
E_WARNING 警告,問題比較嚴重。但是還會繼續向下執行
E_NOTICE 提示,有些小問題不會影響到程式。常發生在專案未定義
E_PARSE 編譯時語法解析錯誤。解析錯誤僅僅由分析器產生。
E_ALL 所有的錯誤
E_STRICT 啟用PHP對程式碼的修改建議,以確保程式碼具有最佳的互操作性和向前相容性。
E_DEPRECATED 啟用後將會對在未來版本中可能無法正常工作的程式碼給出警告。

在上面的幾種型別中:
error最嚴重,必須要解決。不然程式無法繼續向下執行
warning也很重要。通也必須要解決。如果明確的,故意的可以不用處理。
notice 你可以不用管。但是在有些公司,專案標準特別高。在高標準要求的專案中也必須要解決。因為,notice會影響到PHP的執行效率。通常發生在函式未定義等。
parse錯誤,是指語法錯寫錯了,必須要解決,代表全部型別的所有錯誤。

1、 在php.ini中error_reporting引數。如若error_reporting引數設定為0。整個PHP引擎發錯誤均不會顯示、輸出、記錄。在下一章將要講到的日誌記錄中,也不會記錄。
如果我們想顯示所有錯誤可以寫上:
error_reporting = E_ALL
想要顯示所有錯誤但排除提示,可以將這個引數寫為:
error_reporting = E_ALL & ~ E_NOTICE
顯示所有錯誤,但排除提示、相容性和未來相容性。可寫為:
error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED

2、在有些情況下我們無許可權操作php.ini檔案,又想要控制error_reporting怎麼辦呢?
在執行的xxxx.php檔案中開始處,我們可以使用error_reporting()函式達到目標。

<?php

//關閉了所有的錯誤顯示
error_reporting(0);


//顯示所有錯誤
//error_reporting(E_ALL);

//顯示所有錯誤,但不顯示提示
//error_reporting(E_ALL & ~ E_NOTICE);
?>

2. php錯誤處理之錯誤記錄日誌

在一些公司裡面,有專門的日誌收集系統。日誌收集系統會在背後默默的幫你收集錯誤、警告、提示。也有些公司沒有專門的日誌收集系統,通過檔案來伺服器當中的執行日誌。
其中:PHP的錯誤,警告這些是必須要收信的。那麼問題來了——不讓使用者看到,設定好錯誤報告級別好,如何將錯誤收集到日誌系統中呢?

這裡有需要使用到php.ini的相關配置項。這兩個配置項為:

引數 配置項 說明
log_errors on/off 是否開啟日誌記錄
log_errors_max_len 整型,預設1024 單行錯誤最大記錄長度
error_log syslog或者指定路徑 錯誤日誌記錄在什麼地方

說明:
1.在表格中的log_errors和log_errors_max_len非常好理解。
2.而error_log 指定將錯誤存在什麼路徑上。配置項中的syslog可能有點不太好理解。syslog是指系統來記錄。windows系統在電腦的日誌收集器裡面。linux預設在: /etc/syslog.conf
[擴充套件] 瞭解知識點。若Linux系統啟動或修改了日誌收集。可能儲存在第三方專用的日誌收集伺服器中。
此外,PHP還為我們專門準備了一個自定義的錯誤日誌函式:
bool error_log ( string $錯誤訊息 [, int $錯誤訊息型別 = 0 [, string $儲存目標]] )
這個函式可以把錯誤資訊傳送到web伺服器的錯誤日誌,或者到一個檔案裡。

常用的錯誤訊息型別

錯誤訊息型別 說明
0 傳送至預設的error_log指定位置
1 傳送到指定的郵件位置
3 傳送至指定的檔案位置
<?php

//無法連線到資料庫伺服器,直接記錄到php.ini 中的error_log指定位置
error_log("無法連線到資料庫伺服器伺服器");

//可以傳送郵件,但是php.ini必須配置過郵件系統
error_log('可以用郵件報告錯誤,讓運維人員半夜起床幹活',1 ,'[email protected]');

//記錄在指定的位置
error_log("我是一個錯誤喲", 3, "d:/test/my-errors.log");

?>

總結

以上就是今天要講的內容,本文僅僅簡單對之前PHP知識的一些補充,後面可能會用到。