日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

PHP之MVC项目实战(三)

發布時間:2024/7/23 php 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PHP之MVC项目实战(三) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文主要包括以下內容

  • 標準錯誤錯誤處理
  • http操作
  • PDO
  • 文件操作
  • 標準錯誤錯誤處理

    PHP在語法層面上發生的錯誤
    兩個過程:

    觸發階段(發生一個錯誤)
    處理階段(如何處理該錯誤)

    觸發階段

    • 系統觸發,php自己觸發
      典型的都是由php的核心在執行或者編譯php代碼時,發現的錯誤,并觸發該錯誤!

    • 用戶觸發,自定義錯誤
      但是可以通過用戶的php代碼,手動觸發一個錯誤!
      利用函數 trigger_error();觸發一個用戶自定義的錯誤!

    錯誤處理階段

    有三種典型的錯誤處理方法

    第一:報告錯誤信息
    將錯誤信息獲取后,輸出到瀏覽器。
    因此,典型的一個錯誤信息應包含:
    級別,消息,發生的文件,行號:

    想要管理錯誤報告,需要基于錯誤的級別進行管理:
    php允許管理:
    1,是否報告。
    2,報告哪些級別的錯誤。

    利用php的配置:
    display_erorrs:是否顯示錯誤信息,布爾。
    error_reporting:報告的級別!
    需要利用位運算,將所有需要報告的級別都設置上!
    典型的級別是:
    顯示所有的錯誤:

    也可以通過腳本代碼進行以上配置

    ini_set('error_reporting', E_ALL | E_STRICT); ini_set('display_errors', 1);

    第二:錯誤日志
    將錯誤的信息寫到日志文件中!
    也是通過兩個配置完成處理?

    log_errors:是否開啟錯誤日志
    error_log: 錯誤文件位置
    可以同歸ini_set進行配置!

    //錯誤日志 ini_set('error_log', 'e:/php1016/apache/htdocs/test/test.error.log'); ini_set('log_errors', 1);

    error_reporting:針對 錯誤日志同樣有效!

    上面的兩種都是php內置的錯誤方式!

    第三:自定義的錯誤處理
    當觸發錯誤時,php自身不處理,交由用戶腳本代碼進行處理!

    用戶要提供一個方法(函數)來處理發生的錯誤:定義函數!
    告知php,一旦發生錯誤,由用戶定義的函數處理!
    定義一個處理函數:

    設置成錯誤處理器:
    有參數,四個參數:
    級別,消息,文件,行號:

    set_error_handler('user_error_handler'); function user_error_handler($level, $msg, $file, $line) {switch($level) {case E_NOTICE:case E_USER_NOTICE:echo '寫到公告欄中,看到了再解決即可<br>';break;case E_WARNING:case E_USER_WARNING:echo '發一封e-mail,明天加班解決<br>';break;case E_USER_ERROR:echo '發送一個信息,馬上來解決<br>'; // exit;}// return false; }

    用戶定義的處理器一但設置,則系統的(報告,日志)就不可以使用了!
    但是通過使 用戶的錯誤處理器返回 false的形式!。此時錯誤處理繼續交由系統的處理器來處理。

    級別管理
    每個標準錯誤都有一個級別:
    在php中,是采用位運算的形式,管理各個標準的錯誤級別!
    可以在php代碼中通過,php的預定義常量,看到,設置該級別:
    例如:
    系統觸發錯誤典型級別:E_NOTICE, E_WARNING,E_ERROR
    用戶觸發錯誤的典型級別:E_USER_NOTICE, E_USER_WARNING, E_USER_ERROR

    一個典型的是E_ALL,表示所有的錯誤級別:

    操作
    ini_set(‘error_reporting’, 2047);
    開啟所有級別的錯誤:2047 二進制后,所有的位都為1!

    生產環境與開發環境典型錯誤配置:
    生產:開啟所有的錯誤級別,不顯示錯誤信息在頁面上,而記錄在日志內!
    開發:開啟所有級別,顯示在頁面上。關閉錯誤日志!

    項目中增加一個配置項,表示當前的環境模型:
    dev,pro
    增加一個配置項:
    app/config/app.config.php

    然后在framework中初始化

    private static function initErrorHandler() {if('dev' == $GLOBALS['config']['app']['run_mode']) {ini_set('error_reporting', E_ALL | E_STRICT);ini_set('display_errors', 1);ini_set('log_errors', 0);} elseif ('pro' == $GLOBALS['config']['app']['run_mode']) {ini_set('display_errors', 0);ini_set('error_log', APP_DIR . 'error.log');ini_set('log_errors', 1);}}

    致命錯誤的處理
    會終止腳本運行!

    但是如果是用戶定義了錯誤處理器,并且觸發的是用戶的error級別,是可以恢復的(繼續執行)

    但是,系統觸發的致命錯誤,是不能被自定義的處理器所處理的!

    致命錯誤都會終止腳本執行么?
    不是,用戶腳本觸發的致命錯誤在,用戶自定義了錯誤處理器時,可以恢復,腳本繼續運行!

    http操作

    PHP模擬GET請求

    <?php$host_ip = '127.0.0.1'; $port = '80'; if (!$link = fsockopen($host_ip, $port)) {//連接失敗die('連接失敗'); } //var_dump($link);//構建get請求字符串數據 $request_str = 'GET /test.php HTTP/1.1' . "\r\n";//請求行 //請求頭 $request_str .= 'Host: shop.100.com' . "\r\n";//請求主機 $request_str .= 'User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0' . "\r\n";//請求代理標識,模擬的firefox //請求頭以空行結束 $request_str .= "\r\n";//空行 //沒有請求主體 //發請求 $result = fwrite($link, $request_str); //var_dump($result);//等待接收響應數據 echo '<pre>'; echo fread($link, 500); //while (!feof($link)) { // echo fgets($link); //}

    模擬POST請求

    <?php$host_ip = '127.0.0.1'; $port = '80'; if (!$link = fsockopen($host_ip, $port)) {//連接失敗die('連接失敗'); }//post數據 $admin_name = 'admin'; $admin_pass = '1234abcd'; $post_data = 'username='.$admin_name . '&password='.$admin_pass; //username=admin&password=1234abcd//構建post請求字符串數據 $request_str = 'POST /index.php?p=back&c=Admin&a=signin HTTP/1.1' . "\r\n";//請求行 //請求頭 $request_str .= 'Host: shop.100.com' . "\r\n";//請求主機 $request_str .= 'User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0' . "\r\n";//請求代理標識,模擬的firefox //post數據相關的請求頭 $request_str .= 'Content-Type: application/x-www-form-urlencoded' . "\r\n";//post主體數據類型 $request_str .= 'Content-Length: ' . strlen($post_data) . "\r\n"; //請求頭以空行結束 $request_str .= "\r\n";//空行 //請求主體部分 $request_str .= $post_data;//不需要\r\n//發送! fwrite($link, $request_str);//獲得相應數據 echo '<pre>'; //echo fread($link, 8000); while (!feof($link)) {echo fgets($link); }

    http下載
    下載,將服務器端的數據,保存到瀏覽器端!

    http下載,就是將原本應該在瀏覽器上打開的數據數據,讓瀏覽器保存起來即可!

    我們服務器需要工作:
    1,將需要下載的內容輸出到瀏覽器!
    2,告知瀏覽器,接收到的響應數據應該保存起來!、
    利用一個響應頭,Content-disposition: 告知瀏覽器內容的處理方法:
    Content-disposition: attachment 將響應數據作為附件來對待!

    http下載,只是下載的響應主體!

    <?php //test.php得到文件的標識,id //利用id,獲得文件信息。 $img_file = 'E:\php1016\apache\htdocs\shop\app\upload\2013111909\goods_528abce32871b.png';header('Content-Disposition: attachment; filename=' . basename($img_file)); $finfo = finfo_open(FILEINFO_MIME);//獲得一個可以得到文件的MIME信息的資源 $mime = finfo_file($finfo, $img_file);//利用這個資源獲得文件的信息 header('Content-Type: ' . $mime);readfile($img_file);

    curl:client URL
    php的專門用于模擬請求的擴展!
    (curl,獨立工具,php支持curl庫而已)

    使用之前開啟擴展

    <?php$curl = curl_init(); //var_dump($curl);curl_setopt($curl, CURLOPT_URL, 'http://shop.100.com/index.php?p=back&c=Admin&a=signin'); curl_setopt($curl, CURLOPT_POST, true);//false curl_setopt($curl, CURLOPT_POSTFIELDS, array('username'=>'admin', 'password'=>'1234abcd')); curl_setopt($curl, CURLOPT_HEADER, true); //curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_COOKIEJAR, 'e:/php1016/apache/htdocs/test/curl_cookie.txt'); echo '<pre>'; curl_exec($curl);curl_close($curl);

    控制緩存(瀏覽器的緩存
    控制的瀏覽器端的緩存

    典型的響應頭,Expires
    告知瀏覽器,當前你收到的響應數據應該的有效期到什么時候!

    header()函數完成響應頭的設置:

    注意,此時的時間應該是一個格林威治平時
    Tue, 19 Nov 2013 07:27:14 GMT
    因此,Expires也是GMT時間:

    gmdate();與date功能一致,將一個時間戳格式化成一個時間!date格式成本地時間(帶時區的)。而gmdate格式化成一個GMT時間!

    <?phpheader('Expires: ' . gmdate('D, d M Y H:i:s', time()-1) . ' GMT'); header('Cache-Control: no-store no-cache must-revalidate'); echo gmdate('Y-m-d H:i:s'); echo '<br>'; echo gmdate('D, d M Y H:i:s') . ' GMT'; echo '<br>'; echo date('Y-m-d H:i:s'); echo '<hr>'; ?><a href="121.php">self</a>

    防止盜鏈

    利用 請求時攜帶的請求頭:
    referer:表示當前請求的來源!

    只要在請求圖片的響應,判斷一下當前的請求是否是來源本站即可!

    得到來源。判斷來源!

    可以在Apache上,或者 php上都可以!

    對于圖片的請求都是用php生成!

    通過判斷$_SERVER[‘HTTP_REFERER’] 是否是當前網站!

    PDO

    另一種php操作mysql(或其他數據庫)方法

    PHP Data Object
    語法上 是 oop,對象編程(類,方法,屬性,對象)

    PDO 是一個 數據庫抽象層,PDO可以完成對大多數主流數據的操作

    pdo操作具體的數據庫,至少要:
    開啟PDO,同時需要開啟相應的驅動!
    PDO已經內置,mysql的驅動沒有內置!

    extension=php_pdo_mysql.dll

    簡單使用

    /** * @abstract PDO study: PDO操作MySQL增刪查改類 * @date 2014/06/30 * @author Silov[bluebird237@gmail.com] */class mysqlPdoClass{private $db;private $db_name = 'study';private $db_serv;private $db_user = 'root';private $db_pass = 'root';private $db_host = 'localhost';//構造函數以及連接數據庫public function __construct( $username = 'root' , $password = 'root' , $connect = 'false'){$this->db_serv = "mysql:dbname=".$this->db_name.";host=".$this->db_host.";charset=utf-8";$this->db_user = $username;$this->db_pass = $password;}//管理數據庫,析構函數public function __destruct(){$this->db = null;}//執行SQL語句,返回值為sql執行結果public function run_query($sql){$this->db = new PDO($this->db_serv, $this->db_user, $this->db_pass);$this->db->query("set names utf8"); //設置PHP+MySQL連接的編碼格式為UTF8$row = $this->db->query($sql);$row->setFetchMode(PDO::FETCH_ASSOC); //設置查詢結果顯示為鍵值對數組模式return $row;}//執行SQL語句,返回值為sql影響行數public function run_exec($sql){$this->db = new PDO($this->db_serv, $this->db_user, $this->db_pass);$this->db->query("set names utf8"); //設置PHP+MySQL連接的編碼格式為UTF8return $this->db->exec($sql);}/*** @abstract 插入操作* @param $table:表名; $data:插入數據鍵值對數組; $return:是否返回值,為true時,返回插入字段的id; $debug:是否測試,true時返回sql語句,不執行* @return 返回值:插入結果,boolean*/public function data_insert($table, $data, $return = true,$debug=false){if(!$table) {return false;}$fields = array();$values = array();foreach ($data as $field => $value){$fields[] = '`'.$field.'`';$values[] = "'".addslashes($value)."'";}if(empty($fields) || empty($values)) {return false;}$sql = 'INSERT INTO `'.$table.'` ('.join(',',$fields).') VALUES ('.join(',',$values).')';if($debug){return $sql;}$query = $this->run_exec($sql);return $return ? $this->db->lastInsertId() : $query;}/*** @abstract 更新操作* @param $table:表名; $condition:更新查詢條件; $data:更新數據鍵值對數組; $limit:更新數據條數上限* $debug:測試時給true,則不執行update,直接返回完整的sql語句* @return 返回值:插入結果,boolean*/public function data_update($table, $condition, $data, $limit = 1,$debug=false) {if(!$table) {return false;}$set = array();foreach ($data as $field => $value) {$set[] = '`'.$field.'`='."'".addslashes($value)."'";}if(empty($set)) {return false;}$sql = 'UPDATE `'.$table.'` SET '.join(',',$set).' WHERE '.$condition.' '.($limit ? 'LIMIT '.$limit : '');if($debug){return $sql;}return $this->run_exec($sql);}/*** @abstract 查詢單個字段值* @param $sql:sql語句* @return 返回值:string*/public function getOne($sql){$row = $this->run_query($sql);$data = $row->fetch();$data = array_shift($data);return $data;}/*** @abstract 查詢單條記錄,多個字段* @param $sql:sql語句* @return 返回值:鍵值對數組*/public function getRow($sql){$row = $this->run_query($sql);$data = $row->fetch();return $data;}/*** @abstract 查詢多條記錄* @param $sql:sql語句* @return 返回值:以鍵值對數組為元素的數組*/public function getRows($sql){$row = $this->run_query($sql);$data = $row->fetchAll();return $data;} }

    預處理的SQL的執行方式
    如果需要重復地執行結構相同的SQL。此時結構相同的SQL意味著SQL的編譯結果是類似的。除掉數據部分,在做重復的工作!
    應該如何解決?
    將SQL中結構相同的先提取,編譯。
    將不一樣的地方,獨立的處理。
    最后執行將數綁定了的結果可以

    <?php $dsn = 'mysql:dbname=itcast_shop;host=127.0.0.1;port=3306'; $username = 'root'; $password = '123456'; $pdo = new PDO($dsn, $username, $password);//$sql = "insert into it_admin (admin_id, admin_name, admin_pass) values (null, 'itcast', md5('1234abcd'))"; //$rows = $pdo->exec($sql); //$sql = "insert into it_admin (admin_id, admin_name, admin_pass) values (null, 'php', md5('1234abcd'))"; //$rows = $pdo->exec($sql); //$sql = "insert into it_admin (admin_id, admin_name, admin_pass) values (null, '1016', md5('1234abcd'))"; //$rows = $pdo->exec($sql); //$sql = "insert into it_admin (admin_id, admin_name, admin_pass) values (null, 'han', md5('1234abcd'))"; //$rows = $pdo->exec($sql);$sql_struct = "insert into it_admin (admin_id, admin_name, admin_pass) values (null, :name, :pass)";$stmt = $pdo->prepare($sql_struct);$data = array(array('java', '1234'),array('php', '12345'),array('.net', '4567') ); foreach($data as $row) {$stmt->bindValue(':name', $row[0]);$stmt->bindValue(':pass', md5($row[1]));$stmt->execute(); }

    錯誤的處理
    mysql的擴展,錯誤的處理方式不會主動報錯,稱之為 靜默模式。

    pdo的錯誤的處理:默認的也是 靜默模式!
    此時需要使用 錯誤函數獲得錯誤信息:
    pdo?>errorCode();//pdo->errorInfo();//錯誤信息集合

    pdo還支持其他的錯誤模式:
    需要通過修改PDO對象的錯誤模式屬性進行修改:
    pdo?>setAttribute()pdo->setAttribute(屬性名,屬性值);

    靜默模式:Silent mode
    默認的

    警告模式:Warning Mode
    一旦發生錯誤,則觸發一個警告級別的錯誤!

    異常模式:Exception mode
    異常,類似于標準錯誤,是屬于php在處理oop語法時,新的一種錯誤的處理模式!

    分成三個階段進行處理:
    拋出,監聽,捕獲!
    使用如下語法實現:
    拋出:throw
    監聽:try
    捕獲:catch

    拋出的異常,其實就是將所有的錯誤信息封裝到一個異常對象中!
    異常:語法上就是一個 內置的Exception類(其擴展類也算)的對象!

    典型的語法如下:

    <?php$dsn = 'mysql:dbname=itcast_shop;host=127.0.0.1;port=3306'; $username = 'root'; $password = '123456'; $pdo = new PDO($dsn, $username, $password); //設置錯誤模式: //$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); //$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);echo '<pre>'; try {$sql = 'show database';if (!$pdo->query($sql)) {echo $pdo->errorCode();echo '<br>';var_dump($pdo->errorInfo());} } catch (PDOException $e) {echo $e->getMessage(); }

    文件操作

    <? class FSC{// 函數名: getfilesource // 功能: 得到指定文件的內容 // 參數: $file 目標文件 // test passed function getfilesource($file){if($fp=fopen($file,'r')){$filesource=fread($fp,filesize($file));fclose($fp);return $filesource;}elsereturn false; } // 函數名: writefile // 功能: 創建新文件,并寫入內容,如果指定文件名已存在,那將直接覆蓋 // 參數: $file -- 新文件名 // $source 文件內容 //test passed function writefile($file,$source){if($fp=fopen($file,'w')){$filesource=fwrite($fp,$source);fclose($fp);return $filesource;}elsereturn false; } // 函數名: movefile // 功能: 移動文件 // 參數: $file -- 待移動的文件名 // $destfile -- 目標文件名 // $overwrite 如果目標文件存在,是否覆蓋.默認是覆蓋. // $bak 是否保留原文件 默認是不保留即刪除原文件 // test passed function movefile($file,$destfile,$overwrite=1,$bak=0){if(file_exists($destfile)){if($overwrite)unlink($destfile);elsereturn false;}if($cf=copy($file,$destfile)){if(!$bak)return(unlink($file));}return($cf); }// 函數名: movedir // 功能: 這是下一涵數move的附助函數,功能就是移動目錄 function movedir($dir,$destdir,$overwrite=1,$bak=0){@set_time_limit(600);if(!file_exists($destdir))FSC::notfate_any_mkdir($destdir);if(file_exists($dir)&&(is_dir($dir))){if(substr($dir,-1)!='/')$dir.='/';if(file_exists($destdir)&&(is_dir($destdir))){if(substr($destdir,-1)!='/')$destdir.='/';$h=opendir($dir);while($file=readdir($h)){if($file=='.'||$file=='..'){continue;$file="";}if(is_dir($dir.$file)){if(!file_exists($destdir.$file))FSC::notfate_mkdir($destdir.$file);elsechmod($destdir.$file,0777);FSC::movedir($dir.$file,$destdir.$file,$overwrite,$bak);FSC::delforder($dir.$file);}else{if(file_exists($destdir.$file)){if($overwrite)unlink($destdir.$file);else{continue;$file="";}}if(copy($dir.$file,$destdir.$file))if(!$bak)if(file_exists($dir.$file)&&is_file($dir.$file))@unlink($dir.$file);}}}elsereturn false;}elsereturn false; } // 函數名: move // 功能: 移動文件或目錄 // 參數: $file -- 源文件/目錄 // $path -- 目標路徑 // $overwrite -- 如是目標路徑中已存在該文件時,是否覆蓋移動 // -- 默認值是1, 即覆蓋 // $bak -- 是否保留備份(原文件/目錄) function move($file,$path,$overwrite=1,$bak=0){if(file_exists($file)){if(is_dir($file)){if(substr($file,-1)=='/')$dirname=basename(substr($file,0,strlen($file)-1));else $dirname=basename($file);if(substr($path,-1)!='/')$path.='/';if($file!='.'||$file!='..'||$file!='../'||$file!='./')$path.=$dirname;FSC::movedir($file,$path,$overwrite,$bak);if(!$bak)FSC::delforder($file);}else{if(file_exists($path)){if(is_dir($path))chmod($path,0777);else {if($overwrite)@unlink($path);elsereturn false;}}elseFSC::notfate_any_mkdir($path);if(substr($path,-1)!='/')$path.='/';FSC::movefile($file,$path.basename($file),$overwrite,$bak);}}elsereturn false; } // 函數名: delforder // 功能: 刪除目錄,不管該目錄下是否有文件或子目錄,全部刪除哦,小心別刪錯了哦! // 參數: $file -- 源文件/目錄 //test passed function delforder($file) {chmod($file,0777);if (is_dir($file)) {$handle = opendir($file);while($filename = readdir($handle)) {if ($filename != "." && $filename != ".."){FSC::delforder($file."/".$filename);}}closedir($handle);return(rmdir($file));}else {unlink($file);} } // 函數名: notfate_mkdir // 功能: 創建新目錄,這是來自php.net的一段代碼.彌補mkdir的不足. // 參數: $dir -- 目錄名function notfate_mkdir($dir,$mode=0777){$u=umask(0);$r=mkdir($dir,$mode);umask($u);return $r; } // 函數名: notfate_any_mkdir // 功能: 創建新目錄,與上面的notfate_mkdir有點不同,因為它多了一個any,即可以創建多級目錄 // 如:notfate_any_mkdir("abc/abc/abc/abc/abc") // 參數: $dirs -- 目錄名function notfate_any_mkdir($dirs,$mode=0777) {if(!strrpos($dirs,'/')){return(FSC::notfate_mkdir($dirs,$mode));}else{$forder=explode('/',$dirs);$f='';for($n=0;$n<count($forder);$n++){if($forder[$n]=='') continue;$f.=((($n==0)&&($forder[$n]<>''))?(''):('/')).$forder[$n];if(file_exists($f)){chmod($f,0777);continue;}else{if(FSC::notfate_mkdir($f,$mode)) continue;elsereturn false;}}return true;} } } ?>

    總結

    以上是生活随笔為你收集整理的PHP之MVC项目实战(三)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。