Rev 66 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php/*QBPWCF, Quick Build PHP website Component base on Fedora Linux.Copyright (C) 2015~2025 Min-Jhin,ChenThis file is part of QBPWCF.QBPWCF is free software: you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or(at your option) any later version.QBPWCF is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with QBPWCF. If not, see <http://www.gnu.org/licenses/>.*/namespace qbpwcf;#import all lib by composer(include ratchet)require 'composer/vendor/autoload.php';#使用 Ratchet\MessageComponentInterface 界面use Ratchet\MessageComponentInterface;#使用 Ratchet\ConnectionInterface 界面use Ratchet\ConnectionInterface;#用 Chat 類別來實作 MessageComponentInterface 界面class Chat implements MessageComponentInterface{#初始化儲存使用者資訊的陣列private $connInfo=array();#初始化儲存未傳送出去的留言訊息#"fromId",訊息來源的id#"toId",訊息目的的id#"fromUserId",訊息來源的userId#"toUserId",訊息目標的userId#"msg",傳送的訊息private $unSendMsg=array();#初始化一開始尚未能夠連線到資料庫private static $dbTouchable=false;#初始化db的位置public static $dbAddress="localhost";#初始化連線db用的帳戶public static $dbAccount="root";#初始化連線的db名稱public static $dbName="test";#初始化連線db時用的密碼public static $dbPassword="";#初始化連線db的哪個資料表public static $memberTableName="member";#初始化登入時用來驗證帳號的資料表欄位名稱public static $accountCol="account";#初始化登入時用來驗證密碼的資料表欄位名稱,設為""代表不用密碼來認證public static $passwordCol="password";#建構子public function __construct(){#如果尚未可以上資料庫if(!(self::$dbTouchable)){#嘗試連線到目標資料庫.資料表#涵式說明:#一次取得資料庫、表的資料#回傳的結果#$result["status"],執行結果"true"為成功;"false"為執行失敗。#$result["error"],錯誤訊息陣列。#$result["function"],當前執行的漢書名稱.#$result["dataColumnName"],抓取的資料欄位名稱陣列.#$result["dataColumnName"][$i]代表第$i+1個欄位名稱#$result["dataContent"],爲資料的內容。#$result["dataContent"][$conf["WhereColumnName"][$i]][$dataSetNum]#$dataSetNum 爲第$dataSetNum+1筆資料#$conf["WhereColumnName"][$i] 爲第 $i+1 個欄位的名稱#$result["dataCount"],爲取得的資料筆數。#$result["sql"],執行的sql字串.#必填的參數:$conf["db::fastGetDbData"]["dbAddress"]=self::$dbAddress;#爲dbServer的位置。$conf["db::fastGetDbData"]["dbAccount"]=self::$dbAccount;#爲登入dbServer的帳號。$conf["db::fastGetDbData"]["dbName"]=self::$dbName;#爲要存取的資料庫名稱$conf["db::fastGetDbData"]["tableName"]=self::$memberTableName;#爲要存取的資料表名稱$conf["db::fastGetDbData"]["columnYouWant"]=array("id",self::$accountCol);#你想要的欄位!,若設為「array("*")」則代表全部欄位.#如果 $passwordCol 不為空if(self::$passwordCol!=""){#加上密碼欄位$conf["db::fastGetDbData"]["columnYouWant"][]=self::$passwordCol;}#if end#可省略的參數:$conf["db::fastGetDbData"]["dbPassword"]=self::$dbPassword;#爲要存取dbServer的密碼#$conf["db::fastGetDbData"]["WhereColumnName"]=array("account","password");#用於判斷語句的欄位項目陣列。#$conf["db::fastGetDbData"]["WhereColumnValue"]=array($ac,$pw);#用於判斷語句的欄位數值陣列,若與LIKE搭配,則可以在關鍵自字串的左右名加上「%」符號,這樣就可以搜尋具有該字串的內容。#$conf["WhereColumnCombine"]=array("");#用於判斷語句當中需要()起來的判斷式,須爲陣列值,"s"代表「(」,"e"代表「)」 ,若無則須設爲""。#$conf["WhereColumnOperator"]=array("");#用於判斷語句的比較符號陣列,可以用的符號有「"="、"!="、">"、"<"、"LIKE"、"NOT LIKE"」,預設都爲「=」。#$conf["WhereColumnAndOr"]=array("");#用於判斷語句條件之間成立的條件是AND還是OR,須爲陣列值。其數量應爲要判斷的欄位數量減一。#$conf["orderItem"]="";#爲排序的項目依據,若要用隨機抽樣,可以用"rand()",可省略。#$conf["ascORdesc"]="";#爲要低增還是遞減排序,asc爲遞增;desc爲遞減。#$conf["numberStart"]="0";#為從第幾筆開始讀取,預設為0,代筆第一筆。$conf["db::fastGetDbData"]["numLimit"]="1";#為要取幾筆資料,可以省略,省略則表示不限制數目。#$conf["groupBy"]=array("");#爲要以哪幾個欄爲作爲分羣的依據(欄位相同的數值僅會取出一筆)。#備註:#建議在查詢資料前,能夠檢查是否每個欄位都存在.$fastGetDbData=db::fastGetDbData($conf["db::fastGetDbData"]);unset($conf["db::fastGetDbData"]);#如果取得資料失敗if($fastGetDbData["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$fastGetDbData;#印出debug訊息var_dump($result);#結束程式exit;}#if end#連線成功,將self::dbTouchable設為trueself::$dbTouchable=true;}#if end$this->clients = new \SplObjectStorage;}#funciton __construct end#當用戶與伺服器建立連線時public function onOpen(ConnectionInterface $conn){// Store the new connection to send messages to later$this->clients->attach($conn);#提示server有clent連上web socket.echo "New connection! ({$conn->resourceId})\n";#用client的id為index來儲存額外的資訊#元素 "conn" 代表已經建立連線的ConnectionInterface物件#元素 "talkTo" 代表要跟誰講話#元素 "userId" 代表辨識使用者的id#元素 "loigin=array("ac","pw")" 代表client輸入的帳號與密碼#$this->connInfo[$conn->resourceId]=array("conn"=>$conn,"talkTo"=>array(),"userId"=>"","login"=>array("ac"=>"","pw"=>""),"type"=>"");$this->connInfo[$conn->resourceId]=array("conn"=>$conn,"talkTo"=>array(),"userId"=>"","login"=>array("ac"=>"","pw"=>""));#提示登入$conn->send(json_encode("Please input your account! ex:account:ws1"));}#function onOpen end#當伺服器收到訊息時public function onMessage(ConnectionInterface $from, $msg){#如果該連線沒有使用者idif($this->connInfo[$from->resourceId]["userId"]===""){#如果尚未輸入帳戶if($this->connInfo[$from->resourceId]["login"]["ac"]===""){#如果 $msg 長度大於 "account:"if(strlen($msg) > strlen("account:")){#檢查有無前置字元 "account:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="account:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存帳戶$this->connInfo[$from->resourceId]["login"]["ac"]=$delStrBeforeKeyWord["content"];}#if end#反之代表格式錯誤else{#提示輸入帳戶$from->send(json_encode("Please input your account! ex:account:ws1"));#結束程式return true;}#else end}#if end#反之代表輸入錯誤格式的accountelse{#提示輸入帳號$from->send(json_encode("Please input your account! ex:account:ws1"));#結束程式return true;}#else end}#if end#如果有設置密碼欄位if(self::$passwordCol!==""){#如果尚未輸入密碼if($this->connInfo[$from->resourceId]["login"]["pw"]===""){#$msg 長度大於 "password:"if(strlen($msg) > strlen("password:")){#檢查有無前置字元 "password:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="password:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存密碼$this->connInfo[$from->resourceId]["login"]["pw"]=$delStrBeforeKeyWord["content"];}#if end#反之代表格式錯誤else{#提示輸入密碼$from->send(json_encode("Please input your password! ex:password:ws1"));#結束程式return true;}#else end}#if end#反之代表格式錯誤else{#提示輸入密碼$from->send(json_encode("Please input your password! ex:password:ws1"));#結束程式return true;}#else end}#if end}#if end#如果已經輸入帳號了if($this->connInfo[$from->resourceId]["login"]["ac"]!=""){#設置可以進行驗證$startAuth=true;#另存帳號$ac=$this->connInfo[$from->resourceId]["login"]["ac"];#初始化密碼$pw="";#如果有設置密碼欄位if(self::$passwordCol!==""){#如果client已經輸入密碼了if($this->connInfo[$from->resourceId]["login"]["pw"]!=""){#另存密碼$pw=md5($this->connInfo[$from->resourceId]["login"]["pw"]);}#if end#反之else{#設置尚不能進行認證$startAuth=false;}#else end}#if end#如果尚不能進行驗證if(!$startAuth){#結束程式return true;}#if end#檢查有無符合的帳戶密碼#涵式說明:#一次取得資料庫、表的資料#回傳的結果#$result["status"],執行結果"true"為成功;"false"為執行失敗。#$result["error"],錯誤訊息陣列。#$result["function"],當前執行的漢書名稱.#$result["dataColumnName"],抓取的資料欄位名稱陣列.#$result["dataColumnName"][$i]代表第$i+1個欄位名稱#$result["dataContent"],爲資料的內容。#$result["dataContent"][$conf["WhereColumnName"][$i]][$dataSetNum]#$dataSetNum 爲第$dataSetNum+1筆資料#$conf["WhereColumnName"][$i] 爲第 $i+1 個欄位的名稱#$result["dataCount"],爲取得的資料筆數。#$result["sql"],執行的sql字串.#必填的參數:$conf["db::fastGetDbData"]["dbAddress"]=self::$dbAddress;#爲dbServer的位置。$conf["db::fastGetDbData"]["dbAccount"]=self::$dbAccount;#爲登入dbServer的帳號。$conf["db::fastGetDbData"]["dbName"]=self::$dbName;#爲要存取的資料庫名稱$conf["db::fastGetDbData"]["tableName"]=self::$memberTableName;#爲要存取的資料表名稱$conf["db::fastGetDbData"]["columnYouWant"]=array("id");#你想要的欄位!,若設為「array("*")」則代表全部欄位.#可省略的參數:$conf["db::fastGetDbData"]["dbPassword"]=self::$dbPassword;#爲要存取dbServer的密碼$conf["db::fastGetDbData"]["WhereColumnName"]=array(self::$accountCol);#用於判斷語句的欄位項目陣列。$conf["db::fastGetDbData"]["WhereColumnValue"]=array($ac);#用於判斷語句的欄位數值陣列,若與LIKE搭配,則可以在關鍵自字串的左右名加上「%」符號,這樣就可以搜尋具有該字串的內容。#如果有輸入密碼if($pw!==""){#新增要判斷 self::$password 欄位,是否有於 $pw$conf["db::fastGetDbData"]["WhereColumnName"][]=self::$passwordCol;$conf["db::fastGetDbData"]["WhereColumnValue"][]=$pw;}#if end#$conf["WhereColumnCombine"]=array("");#用於判斷語句當中需要()起來的判斷式,須爲陣列值,"s"代表「(」,"e"代表「)」 ,若無則須設爲""。#$conf["WhereColumnOperator"]=array("");#用於判斷語句的比較符號陣列,可以用的符號有「"="、"!="、">"、"<"、"LIKE"、"NOT LIKE"」,預設都爲「=」。#$conf["WhereColumnAndOr"]=array("");#用於判斷語句條件之間成立的條件是AND還是OR,須爲陣列值。其數量應爲要判斷的欄位數量減一。#$conf["orderItem"]="";#爲排序的項目依據,若要用隨機抽樣,可以用"rand()",可省略。#$conf["ascORdesc"]="";#爲要低增還是遞減排序,asc爲遞增;desc爲遞減。#$conf["numberStart"]="0";#為從第幾筆開始讀取,預設為0,代筆第一筆。$conf["db::fastGetDbData"]["numLimit"]="1";#為要取幾筆資料,可以省略,省略則表示不限制數目。#$conf["groupBy"]=array("");#爲要以哪幾個欄爲作爲分羣的依據(欄位相同的數值僅會取出一筆)。#備註:#建議在查詢資料前,能夠檢查是否每個欄位都存在.$fastGetDbData=db::fastGetDbData($conf["db::fastGetDbData"]);unset($conf["db::fastGetDbData"]);#如果取得資料失敗if($fastGetDbData["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$fastGetDbData;#印出結果#var_dump($result);#提示server有資料庫錯誤echo "dbError!";#結束程式exit;}#if end#如果沒有一筆資料if($fastGetDbData["dataCount"]!==1){#代表登入失敗#清空登入用的帳戶$this->connInfo[$from->resourceId]["login"]["ac"]="";#清空登入用的密碼$this->connInfo[$from->resourceId]["login"]["pw"]="";#提示登入失敗$from->send(json_encode("Login failed, please input account. ex:account:ws1"));#執行到這即可return true;}#if end#反之代表帳戶資訊正確else{#設置 $myUserId$myUserId=$this->connInfo[$from->resourceId]["userId"]=$fastGetDbData["dataContent"]["id"][0];#設置 $myId$myId=$from->resourceId;#提示登入成功$from->send(json_encode("Login successfully!"));#檢查是否有訊息是要給自己的foreach($this->unSendMsg as $index => $historyMsg){#如果有要給自己的訊息if($myUserId===$historyMsg["toUserId"]){#接收別人給的留言$from->send(json_encode($historyMsg["msg"]));#有幾個人在線上就執行幾次foreach($this->connInfo as $toId => $cInfo){#如果是自己if($myId===$toId ){#跳過continue;}#if end#如果留言的對象有在線上if($historyMsg["fromUserId"]===$cInfo["userId"]){#檢查對方是否已經在自己的通話清單裡面了#初始化要將對方加到自己的對話清單裡面$add=false;#根據自己的每個通話對象foreach($this->connInfo[$myId]["talkTo"] as $myToIndex=>$myToCinfo ){#如果對對方已經存在於自己的對話清單裡面了if($myToCinfo["userId"]===$historyMsg["fromUserId"] && $myId===$historyMsg["fromId"]){#設置不要將對方加到自己的對話清單裡面$add=false;#跳出foreachbreak;}#if end}#foreach end#如果要將對方加到自己的對話清單裡面if($add){#將對方加到自己的talkTo清單裡面$this->connInfo[$myId]["talkTo"][]=array("id"=>$toId,"userId"=>$historyMsg["fromUserId"]);}#if end#檢查自己有沒有在對方talkTo清單裡面#假設對方需要加自己到對話清單裡面$add=true;#檢查通話對象能否跟自己對話#依據對方每個通話的對象foreach($this->connInfo[$toId]["talkTo"] as $talkToIndex=>$talkToCinfo){#如果自己的userId已經在對方的對話清單裡面了if($myUserId===$talkToCinfo["userId"]){#如果對方對話userId對應的id不在線上if(!isset($this->connInfo[$toId])){#檢查對方對話清單是否已經含有自己的id與userId了#假設對方對話清單沒有自己的id與userId$update=true;#依據對方每個通話的對象foreach($this->connInfo[$toId]["talkTo"] as $ceToIndex=>$ceToCinfo){#如果對方對話清單已經含有自己的id與userId了if($ceToCinfo["id"]===$myId && $ceToCinfo["userId"]===$myUserId){#設置不需要更新$update=false;#設置對方不需要加自己到對話清單裡面$add=false;}#if end}#foreach end#如果對方對話清單沒有自己的id與userIdif($update){#將自己在對方對話清單裡面的id改成現在的id$this->connInfo[$toId]["talkTo"][$talkToIndex]["id"]=$myId;}#if end#反之對方對話清單已經有自己的id與userIdelse{#移除對方該已經斷線的對話idunset($this->connInfo[$toId]["talkTo"][$talkToIndex]);}#else end}#if end}#if end}#foreach end#如果對方需要加自己到對話清單裡面if($add){#讓通話對象也可以傳送訊息回來$this->connInfo[$toId]["talkTo"][]=array("id"=>$myId,"userId"=>$myUserId);}#if end}#if end}#foreach end#移除留言紀錄unset($this->unSendMsg[$index]);}#if end}#foreach end#檢查線上是否有人想跟我對話#有幾個人在線上就執行幾次foreach($this->connInfo as $toId => $cInfo){#如果是自己if($myId===$toId){#跳過continue;}#if end#該cliet目前再跟幾個人通話,就執行幾次foreach($cInfo["talkTo"] as $tIndex=>$tInfo){#如果自己的userId在對方的對話清單裡面if($myUserId===$tInfo["userId"]){#假設自己需要被對方加到對話清單裡面$add=true;#檢查自己是否已經在對方的對話清單裡面#對方有幾個通話對象就執行幾次foreach($this->connInfo[$toId]["talkTo"] as $toIndex=>$toCinfo){#如果自己已經在對方的對話清單裡面if($myUserId===$toCinfo["userId"] && $myId===$toCinfo["id"]){#設置自己不需要被對方加到對話清單裡面$add=false;#跳出迴圈break;}#if end}#foreach end#另存針對自己userId的連線id$oneIdOfMyUserid=$this->connInfo[$toId]["talkTo"][$tIndex]["id"];#如果對方對話清單裡面的用戶id不在線if(!isset($this->connInfo[$oneIdOfMyUserid])){#假設要將自己在對方對話清單裡面的id改成現在的id$update=true;#自己不需要被對方加到對話清單裡面$add=false;#檢查自己的id是否已經在對方的對話id裡面foreach($this->connInfo[$toId]["talkTo"] as $ceIndex=>$ceInfo){#如果自己的id已經在對方的對話清單裡面if($myId===$ceInfo["id"]){#設置不要將自己在對方對話清單裡面的id改成現在的id(可以移除該對話id)$update=false;#跳出迴圈break;}#if end}#foreach end#如果要將自己在對方對話清單裡面的id改成現在的idif($update){#將自己在對方對話清單裡面的id改成現在的id$this->connInfo[$toId]["talkTo"][$tIndex]["id"]=$myId;}#if end#反之不要將自己在對方對話清單裡面的id改成現在的id(可以移除該對話id)else{#移除該對話idunset($this->connInfo[$toId]["talkTo"][$tIndex]);}#else end}#if end#如果要將自己加到對方的的通話清單裡面if($add){#將自己加到對方的的通話清單裡面$this->connInfo[$toId]["talkTo"][]=array("id"=>$myId,"userId"=>$myUserId);}#if end#檢查對方是否已經在自己的對話清單裡面#設置要新增對方到自己的對話清單裡面.$add=true;#自己有幾個對話對象就執行幾次foreach($this->connInfo[$myId]["talkTo"] as $mtIndex=>$mtInfo){#對方的userId與id若在自己的對話清單裡面if($mtInfo["userId"]===$cInfo["userId"] && $mtInfo["id"]===$toId){#設置不需要新增對方到自己的對話清單裡面$add=false;#跳出 foreachbreak;}#if end}#foreache end#如果要新增對方到自己的對話清單裡面.if($add){#將對方加到自己的對話清單裡面$this->connInfo[$myId]["talkTo"][]=array("id"=>$toId,"userId"=>$cInfo["userId"]);}#if end}#if end}#foreach end}#foreach end#結束認證成功後的流程return true;}#else end}#else end#結束認證流程return true;}#if end#如果收到 "id?"else if($msg==="id?"){#傳他人的id給client$from->send(json_encode($from->resourceId));#回傳成功return true;}#if end#如果收到 "ids?"else if($msg==="ids?"){#初始化儲存其他人的id$idsArray=array();#針對所的clientforeach ($this->clients as $client){#排除自己if($from !== $client){#取得其他人的id$idsArray[]=$client->resourceId;}#if end}#foreach end#傳他人的id給client$from->send(json_encode($idsArray));#回傳成功return true;}#if end#如果收到 "talkTo?"else if($msg==="talkTo?"){#正在對話的對象id給client$from->send(json_encode($this->connInfo[$from->resourceId]["talkTo"]));#回傳成功return true;}#if end#如果收到的$msg長度大於 "talkTo:"if(strlen($msg)>strlen("talkTo:")){#如果收到開頭為 "talkTo:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="talkTo:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "talkTo:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "talkTo:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "talkTo:" 分割 $buf#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="talkTo:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果剛好分割出一筆資料if($spiltString["dataCounts"]===1){#取得自己的id$myId=$from->resourceId;#取得講話對象的id$toId=$spiltString["dataArray"][0];#設置對象不存在的識別$targetExist=false;#設置通話對象的key$targetKey="";#如果要對話的對象存在if(isset($this->connInfo[$toId])){#取得對象的userId$toUserId=$this->connInfo[$toId]["userId"];#取得同userId的對象id們#初始化同userId的對象id$targetC=array();#針對每個連線foreach($this->connInfo as $eachIndex=>$eachInfo){#如果是自己if($eachIndex===$myId){#跳到下一輪continue;}#if end#如果是同userId的對象if($eachInfo["userId"]===$toUserId){#取出連線$targetC[$eachIndex]=$this->connInfo[$eachIndex];}#if end}#foreach end#針對每個同userId的連線foreach($targetC as $tcIndex=>$tcInfo){#檢查自己的對話對象是否已經在清單裡面了#假設對象可以加到自己對話清單裡面$add=true;#針對每個要講話的對象foreach($this->connInfo[$myId]["talkTo"] as $index=>$cInfo){#如果對話對象已經在清單裡面了if($this->connInfo[$tcIndex]["userId"]===$cInfo["userId"] && $tcIndex===$cInfo["id"]){#設置不要再加到清單裡面$add=false;#跳出foreachbreak;}#if end}#foreach end#如果要加入到對話清單裡面if($add){#增加自己的對話對象$this->connInfo[$myId]["talkTo"][]=array("id"=>$tcIndex,"userId"=>$this->connInfo[$tcIndex]["userId"]);#假設對方可以加自己到對話清單裡面$add=true;#檢查通話對象能否跟自己對話foreach($this->connInfo[$tcIndex]["talkTo"] as $index=>$cInfo){#如果對話對象已經在清單裡面了if($this->connInfo[$myId]["userId"]===$cInfo["userId"]){#設置不要再加到清單裡面$add=false;#跳出 foreachbreak;}#if end}#foreach end#如果對方可以加自己到對話清單裡面if($add){#讓通話對象也可以傳送訊息回來$this->connInfo[$tcIndex]["talkTo"][]=array("id"=>$myId,"userId"=>$this->connInfo[$myId]["userId"]);}#if end#設置要給自己看的訊息$from->send(json_encode("true"));}#if end#反之else{#設置要給自己看的訊息$from->send(json_encode("false"));}#else end}#foreach end#回傳成功return true;}#if end#反之不存在else{#設置要給自己看的訊息$from->send(json_encode("false"));#回傳成功return true;}#else end}#if end}#if end}#if end#如果有要講話的對象if(count($this->connInfo[$from->resourceId]["talkTo"])>0){#依據每個對話對象foreach($this->connInfo[$from->resourceId]["talkTo"] as $index => $cInfo){#如果要講話的對象不存在(socket已經斷開)if(!isset($this->connInfo[$cInfo["id"]])){#將訊息儲存起來,等對象上線後再把訊息傳過去.$this->unSendMsg[]=array("fromId"=>$from->resourceId,"toId"=>"","fromUserId"=>$this->connInfo[$from->resourceId]["userId"],"toUserId"=>$cInfo["userId"],"msg"=>$msg);}#if end#反之else{#另存 ConnectionInterface 物件$connObject=$this->connInfo[$cInfo["id"]]["conn"];#傳送訊息給對方$snedResult=$connObject->send(json_encode($msg));}#else end}#foreach end}#if end#反之沒有講話的對象else{#提示server訊息被拋棄echo "Message 「".$msg."」 will not be received by any one";#設置要給自己看的訊息$from->send(json_encode("false"));}#else end}#function onMessage end#當clinet的連線斷掉前public function onClose(ConnectionInterface $conn){// The connection is closed, remove it, as we can no longer send it messages$this->clients->detach($conn);echo "Connection {$conn->resourceId} has disconnected\n";#移除連線的資訊unset($this->connInfo[$conn->resourceId]);}#function onClose end#當出現錯誤時public function onError(ConnectionInterface $conn, \Exception $e){echo "An error has occurred: {$e->getMessage()}\n";$conn->close();}#fucntion onError end}#class Chat end#用 ChatV2 類別來實作 MessageComponentInterface 界面,#改善了用戶網路斷掉但Server端不會將連線斷掉的問題#改善了用戶端網路恢復後無法收到之前未收到的訊息的問題class ChatV2 implements MessageComponentInterface{#初始化儲存使用者資訊的陣列private $connInfo=array();#初始化儲存未傳送出去的留言訊息#"fromId",訊息來源的id#"toId",訊息目的的id#"fromUserId",訊息來源的userId#"toUserId",訊息目標的userId#"msg",傳送的訊息private $unSendMsg=array();#初始化儲存待確認是否送達到對方的訊息#$unConfirmMsg[$id],$id為訊息接收方,亦即收到訊息後,要跟server說有收到訊息者.#"fromId",訊息來源的id#"toId",訊息目的的id#"fromUserId",訊息來源的userId#"toUserId",訊息目標的userId#"msg",傳送的訊息private $unConfirmMsg=array();#初始化一開始尚未能夠連線到資料庫private static $dbTouchable=false;#初始化db的位置public static $dbAddress="localhost";#初始化連線db用的帳戶public static $dbAccount="root";#初始化連線的db名稱public static $dbName="test";#初始化連線db時用的密碼public static $dbPassword="";#初始化連線db的哪個資料表public static $memberTableName="member";#初始化登入時用來驗證帳號的資料表欄位名稱public static $accountCol="account";#初始化登入時用來驗證密碼的資料表欄位名稱,設為""代表不用密碼來認證public static $passwordCol="password";#建構子public function __construct(){#如果尚未可以上資料庫if(!(self::$dbTouchable)){#嘗試連線到目標資料庫.資料表#涵式說明:#一次取得資料庫、表的資料#回傳的結果#$result["status"],執行結果"true"為成功;"false"為執行失敗。#$result["error"],錯誤訊息陣列。#$result["function"],當前執行的漢書名稱.#$result["dataColumnName"],抓取的資料欄位名稱陣列.#$result["dataColumnName"][$i]代表第$i+1個欄位名稱#$result["dataContent"],爲資料的內容。#$result["dataContent"][$conf["WhereColumnName"][$i]][$dataSetNum]#$dataSetNum 爲第$dataSetNum+1筆資料#$conf["WhereColumnName"][$i] 爲第 $i+1 個欄位的名稱#$result["dataCount"],爲取得的資料筆數。#$result["sql"],執行的sql字串.#必填的參數:$conf["db::fastGetDbData"]["dbAddress"]=self::$dbAddress;#爲dbServer的位置。$conf["db::fastGetDbData"]["dbAccount"]=self::$dbAccount;#爲登入dbServer的帳號。$conf["db::fastGetDbData"]["dbName"]=self::$dbName;#爲要存取的資料庫名稱$conf["db::fastGetDbData"]["tableName"]=self::$memberTableName;#爲要存取的資料表名稱$conf["db::fastGetDbData"]["columnYouWant"]=array("id",self::$accountCol);#你想要的欄位!,若設為「array("*")」則代表全部欄位.#如果 $passwordCol 不為空if(self::$passwordCol!=""){#加上密碼欄位$conf["db::fastGetDbData"]["columnYouWant"][]=self::$passwordCol;}#if end#可省略的參數:$conf["db::fastGetDbData"]["dbPassword"]=self::$dbPassword;#爲要存取dbServer的密碼#$conf["db::fastGetDbData"]["WhereColumnName"]=array("account","password");#用於判斷語句的欄位項目陣列。#$conf["db::fastGetDbData"]["WhereColumnValue"]=array($ac,$pw);#用於判斷語句的欄位數值陣列,若與LIKE搭配,則可以在關鍵自字串的左右名加上「%」符號,這樣就可以搜尋具有該字串的內容。#$conf["WhereColumnCombine"]=array("");#用於判斷語句當中需要()起來的判斷式,須爲陣列值,"s"代表「(」,"e"代表「)」 ,若無則須設爲""。#$conf["WhereColumnOperator"]=array("");#用於判斷語句的比較符號陣列,可以用的符號有「"="、"!="、">"、"<"、"LIKE"、"NOT LIKE"」,預設都爲「=」。#$conf["WhereColumnAndOr"]=array("");#用於判斷語句條件之間成立的條件是AND還是OR,須爲陣列值。其數量應爲要判斷的欄位數量減一。#$conf["orderItem"]="";#爲排序的項目依據,若要用隨機抽樣,可以用"rand()",可省略。#$conf["ascORdesc"]="";#爲要低增還是遞減排序,asc爲遞增;desc爲遞減。#$conf["numberStart"]="0";#為從第幾筆開始讀取,預設為0,代筆第一筆。$conf["db::fastGetDbData"]["numLimit"]="1";#為要取幾筆資料,可以省略,省略則表示不限制數目。#$conf["groupBy"]=array("");#爲要以哪幾個欄爲作爲分羣的依據(欄位相同的數值僅會取出一筆)。#備註:#建議在查詢資料前,能夠檢查是否每個欄位都存在.$fastGetDbData=db::fastGetDbData($conf["db::fastGetDbData"]);unset($conf["db::fastGetDbData"]);#如果取得資料失敗if($fastGetDbData["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$fastGetDbData;#印出debug訊息var_dump($result);#結束程式exit;}#if end#連線成功,將self::dbTouchable設為trueself::$dbTouchable=true;}#if end$this->clients = new \SplObjectStorage;}#funciton __construct end#當用戶與伺服器建立連線時public function onOpen(ConnectionInterface $conn){// Store the new connection to send messages to later$this->clients->attach($conn);#提示server有clent連上web socket.echo "New connection! ({$conn->resourceId})\n";#用client的id為index來儲存額外的資訊#元素 "conn" 代表已經建立連線的ConnectionInterface物件#元素 "talkTo" 代表要跟誰講話#元素 "userId" 代表辨識使用者的id#元素 "loigin=array("ac","pw")" 代表client輸入的帳號與密碼#元素 "msgId" 為用來識別待確認訊息的索引#元素 "gotMsgId" 為用來識別是否已經設置過 msgId 了#$this->connInfo[$conn->resourceId]=array("conn"=>$conn,"talkTo"=>array(),"userId"=>"","login"=>array("ac"=>"","pw"=>""),"type"=>"");$this->connInfo[$conn->resourceId]=array("conn"=>$conn,"talkTo"=>array(),"userId"=>"","login"=>array("ac"=>"","pw"=>""),"msgId"=>"","gotMsgId"=>"false");#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your account! ex:account:ws1");#提示輸入帳號$conn->send(json_encode($packedMsg));}#function onOpen end#當伺服器收到訊息時public function onMessage(ConnectionInterface $from, $msg){#debug#$array=array("msgId"=>$this->connInfo[$from->resourceId]["msgId"],"resourceId"=>$from->resourceId,"msg"=>$msg);#var_dump($array);#如果該連線沒有使用者idif($this->connInfo[$from->resourceId]["userId"]===""){#代表需要認證,認證的會員資料表 slef::memberTableName,需要以下三個欄位.#id 自訂#account 自訂#password varchar(33)/*#如果尚未輸入用戶端類型if($this->connInfo[$from->resourceId]["type"]===""){#如果 $msg 長度大於 "type:"if(strlen($msg) > strlen("type:")){#檢查有無前置字元 "account:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="type:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存用戶端類型$this->connInfo[$from->resourceId]["type"]=$delStrBeforeKeyWord["content"];}#if end#反之else{#提示輸入用戶端類型$from->send(json_encode("Please input your type! ex:type:user"));#結束程式return true;}#else end}#if end#反之代表輸入錯誤格式的typeelse{#提示輸入用戶端類型$from->send(json_encode("Please input your type! ex:type:user"));#結束程式return true;}#else end}#if end#如果用戶端是"user"if($this->connInfo[$from->resourceId]["type"]==="user"){#...}#if end#反之如果用戶端是"device"else if($this->connInfo[$from->resourceId]["type"]==="device"){#...}#if end*/#如果尚未輸入帳戶if($this->connInfo[$from->resourceId]["login"]["ac"]===""){#如果 $msg 長度大於 "account:"if(strlen($msg) > strlen("account:")){#檢查有無前置字元 "account:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="account:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存帳戶$this->connInfo[$from->resourceId]["login"]["ac"]=$delStrBeforeKeyWord["content"];}#if end#反之代表格式錯誤else{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your account! ex:account:ws1");#提示輸入帳號$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#反之代表輸入錯誤格式的accountelse{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your account! ex:account:ws1");#提示輸入帳號$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#如果有設置密碼欄位if(self::$passwordCol!==""){#如果尚未輸入密碼if($this->connInfo[$from->resourceId]["login"]["pw"]===""){#$msg 長度大於 "password:"if(strlen($msg) > strlen("password:")){#檢查有無前置字元 "password:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="password:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存密碼$this->connInfo[$from->resourceId]["login"]["pw"]=$delStrBeforeKeyWord["content"];}#if end#反之代表格式錯誤else{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your password! ex:password:ws1");#提示輸入密碼$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#反之代表格式錯誤else{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your password! ex:password:ws1");#提示輸入密碼$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end}#if end#如果已經輸入帳號了if($this->connInfo[$from->resourceId]["login"]["ac"]!=""){#設置可以進行驗證$startAuth=true;#另存帳號$ac=$this->connInfo[$from->resourceId]["login"]["ac"];#初始化密碼$pw="";#如果有設置密碼欄位if(self::$passwordCol!==""){#如果client已經輸入密碼了if($this->connInfo[$from->resourceId]["login"]["pw"]!=""){#另存密碼$pw=md5($this->connInfo[$from->resourceId]["login"]["pw"]);}#if end#反之else{#設置尚不能進行認證$startAuth=false;}#else end}#if end#如果尚不能進行驗證if(!$startAuth){#結束程式return true;}#if end#檢查有無符合的帳戶密碼#涵式說明:#一次取得資料庫、表的資料#回傳的結果#$result["status"],執行結果"true"為成功;"false"為執行失敗。#$result["error"],錯誤訊息陣列。#$result["function"],當前執行的漢書名稱.#$result["dataColumnName"],抓取的資料欄位名稱陣列.#$result["dataColumnName"][$i]代表第$i+1個欄位名稱#$result["dataContent"],爲資料的內容。#$result["dataContent"][$conf["WhereColumnName"][$i]][$dataSetNum]#$dataSetNum 爲第$dataSetNum+1筆資料#$conf["WhereColumnName"][$i] 爲第 $i+1 個欄位的名稱#$result["dataCount"],爲取得的資料筆數。#$result["sql"],執行的sql字串.#必填的參數:$conf["db::fastGetDbData"]["dbAddress"]=self::$dbAddress;#爲dbServer的位置。$conf["db::fastGetDbData"]["dbAccount"]=self::$dbAccount;#爲登入dbServer的帳號。$conf["db::fastGetDbData"]["dbName"]=self::$dbName;#爲要存取的資料庫名稱$conf["db::fastGetDbData"]["tableName"]=self::$memberTableName;#爲要存取的資料表名稱$conf["db::fastGetDbData"]["columnYouWant"]=array("id");#你想要的欄位!,若設為「array("*")」則代表全部欄位.#可省略的參數:$conf["db::fastGetDbData"]["dbPassword"]=self::$dbPassword;#爲要存取dbServer的密碼$conf["db::fastGetDbData"]["WhereColumnName"]=array(self::$accountCol);#用於判斷語句的欄位項目陣列。$conf["db::fastGetDbData"]["WhereColumnValue"]=array($ac);#用於判斷語句的欄位數值陣列,若與LIKE搭配,則可以在關鍵自字串的左右名加上「%」符號,這樣就可以搜尋具有該字串的內容。#如果有輸入密碼if($pw!==""){#新增要判斷 self::$password 欄位,是否有於 $pw$conf["db::fastGetDbData"]["WhereColumnName"][]=self::$passwordCol;$conf["db::fastGetDbData"]["WhereColumnValue"][]=$pw;}#if end#$conf["WhereColumnCombine"]=array("");#用於判斷語句當中需要()起來的判斷式,須爲陣列值,"s"代表「(」,"e"代表「)」 ,若無則須設爲""。#$conf["WhereColumnOperator"]=array("");#用於判斷語句的比較符號陣列,可以用的符號有「"="、"!="、">"、"<"、"LIKE"、"NOT LIKE"」,預設都爲「=」。#$conf["WhereColumnAndOr"]=array("");#用於判斷語句條件之間成立的條件是AND還是OR,須爲陣列值。其數量應爲要判斷的欄位數量減一。#$conf["orderItem"]="";#爲排序的項目依據,若要用隨機抽樣,可以用"rand()",可省略。#$conf["ascORdesc"]="";#爲要低增還是遞減排序,asc爲遞增;desc爲遞減。#$conf["numberStart"]="0";#為從第幾筆開始讀取,預設為0,代筆第一筆。$conf["db::fastGetDbData"]["numLimit"]="1";#為要取幾筆資料,可以省略,省略則表示不限制數目。#$conf["groupBy"]=array("");#爲要以哪幾個欄爲作爲分羣的依據(欄位相同的數值僅會取出一筆)。#備註:#建議在查詢資料前,能夠檢查是否每個欄位都存在.$fastGetDbData=db::fastGetDbData($conf["db::fastGetDbData"]);unset($conf["db::fastGetDbData"]);#如果取得資料失敗if($fastGetDbData["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$fastGetDbData;#提示server有資料庫錯誤echo "dbError!";#結束程式exit;}#if end#如果沒有一筆資料if($fastGetDbData["dataCount"]!==1){#代表登入失敗#清空登入用的帳戶$this->connInfo[$from->resourceId]["login"]["ac"]="";#清空登入用的密碼$this->connInfo[$from->resourceId]["login"]["pw"]="";#包裝訊息#"type"為"login"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"false","data"=>"Login failed, please input account. ex:account:ws1");#提示登入失敗$from->send(json_encode($packedMsg));#執行到這即可return true;}#if end#反之代表帳戶資訊正確else{#設置 $myUserId$myUserId=$this->connInfo[$from->resourceId]["userId"]=$fastGetDbData["dataContent"]["id"][0];#設置 $myId$myId=$from->resourceId;#初始化msgId的部份內容$msgId=$myUserId."-";#初始化儲存msgId的陣列$msgIdArray=array();#取得所有client的msgIdforeach($this->connInfo as $clientInfoArray){#如果msgId不為""if($clientInfoArray["msgId"]!==""){#取得msgId$msgIdArray[]=$clientInfoArray["msgId"];}#if end}#foreach end#如果尚未產生完整的msgId或msgId有重複while($msgId===$myUserId."-" || in_array($msgId,$msgIdArray)){#涵式說明:#建立以圖片(PNG格式)呈現的驗證碼.#回傳的解果:#$result["status"],執行是否正常,"true"代表執行成功,"false"代表執行失敗.#$result["error"],錯誤訊息.#$result["function"],檔前執行的函數名稱.#$result["randNumberWord"],傳驗證碼的內容.#$result["imgAddress"],圖片的位置與名稱.#必填的參數:#$conf["imgAddressAndName"],字串,爲驗證碼圖片儲存的位置與名稱,副檔名程式會自動產生$conf["authenticate::validationCode"]["imgAddressAndName"]="no used!";#$conf["fileArgu"],字串,php變數__FILE__的內容,亦即該檔案在檔案系統的絕對路徑$conf["authenticate::validationCode"]["fileArgu"]="no used!";#可省略的參數:#$conf["num"],字串,爲驗證碼的位數,請輸入阿拉伯數字,預設為"8"位數.#$conf["num"]="8";#$conf["disableImg"],字串,是否要取消驗證碼圖片的輸出,"true"為要取消,預設為"false"為不取消$conf["authenticate::validationCode"]["disableImg"]="true";#$conf["imgToData"],字串,預設為"true"代表將圖片轉存成base64圖片,並將原始圖片移除;反之為"false"#$conf["imgToData"]="true";$validationCode=authenticate::validationCode($conf["authenticate::validationCode"]);unset($conf["authenticate::validationCode"]);#如果產生亂數失敗if($validationCode["status"]==="false"){#設置錯誤狀態$result["status"]="false";#設置錯誤提示$result["error"]=$validationCode;#印出錯誤訊息var_dump($result);#回傳結果return $result;}#if end#儲存產生好的msgId$msgId=$myUserId."-".$validationCode["randNumberWord"];}#while end#設置獨立於id與userId且用於驗證訊息是否收到的msgId$this->connInfo[$from->resourceId]["msgId"]=$msgId;#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Login successfully!");#提示登入成功$from->send(json_encode($packedMsg));#檢查是否有訊息是要給自己的foreach($this->unSendMsg as $index => $historyMsg){#如果有要給自己的訊息if($myUserId===$historyMsg["toUserId"]){#包裝訊息#"type"為"unSendMsg?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"unSendMsg?","status"=>"true","data"=>$historyMsg["msg"]);#接收別人給的留言$from->send(json_encode($packedMsg));#有幾個人在線上就執行幾次foreach($this->connInfo as $toId => $cInfo){#如果是自己if($myId===$toId ){#跳過continue;}#if end#如果留言的對象有在線上if($historyMsg["fromUserId"]===$cInfo["userId"]){#檢查對方是否已經在自己的通話清單裡面了#初始化要將對方加到自己的對話清單裡面$add=false;#根據自己的每個通話對象foreach($this->connInfo[$myId]["talkTo"] as $myToIndex=>$myToCinfo ){#如果對對方已經存在於自己的對話清單裡面了if($myToCinfo["userId"]===$historyMsg["fromUserId"] && $myId===$historyMsg["fromId"]){#設置不要將對方加到自己的對話清單裡面$add=false;#跳出foreachbreak;}#if end}#foreach end#如果要將對方加到自己的對話清單裡面if($add){#將對方加到自己的talkTo清單裡面$this->connInfo[$myId]["talkTo"][]=array("id"=>$toId,"userId"=>$historyMsg["fromUserId"],"msgId"=>$this->connInfo[$toId]["msgId"]);}#if end#檢查自己有沒有在對方talkTo清單裡面#假設對方需要加自己到對話清單裡面$add=true;#檢查通話對象能否跟自己對話#依據對方每個通話的對象foreach($this->connInfo[$toId]["talkTo"] as $talkToIndex=>$talkToCinfo){#如果自己的userId已經在對方的對話清單裡面了if($myUserId===$talkToCinfo["userId"]){#如果對方對話userId對應的id不在線上if(!isset($this->connInfo[$toId])){#debug#var_dump("對方對話userId(".$talkToCinfo["userId"].")應的id(".$toId.")不在線上");#檢查對方對話清單是否已經含有自己的id與userId了#假設對方對話清單沒有自己的id與userId$update=true;#依據對方每個通話的對象foreach($this->connInfo[$toId]["talkTo"] as $ceToIndex=>$ceToCinfo){#如果對方對話清單已經含有自己的id與userId了if($ceToCinfo["id"]===$myId && $ceToCinfo["userId"]===$myUserId){#debug#var_dump("對方對話清單已經含有自己的id(".$myId.")與userId了(".$myUserId.")");#設置不需要更新$update=false;#debug#var_dump($toId."要加".$myId."到通話清單裡面");#設置對方不需要加自己到對話清單裡面$add=false;}#if end}#foreach end#如果對方對話清單沒有自己的id與userId與msgIdif($update){#debug#var_dump($toId."要更新對話清單中索引為".$talkToIndex."的id(".$this->connInfo[$toId]["talkTo"][$talkToIndex]["id"].")為".$myId);#將自己在對方對話清單裡面的id改成現在的id$this->connInfo[$toId]["talkTo"][$talkToIndex]["id"]=$myId;}#if end#反之對方對話清單已經有自己的id與userIdelse{#移除對方該已經斷線的對話idunset($this->connInfo[$toId]["talkTo"][$talkToIndex]);}#else end}#if end}#if end}#foreach end#如果對方需要加自己到對話清單裡面if($add){#檢查對方每個通話對象foreach($this->connInfo[$toId]["talkTo"] as $reCktIndex=>$reCktInfo){#如果已經有將自己加到對方的對話清單裡面if($reCktInfo["id"]===$myId && $reCktInfo["userId"]===$myUserId){#設置不用將自己加到對方的對話清單裡面$add=false;}#if end}#foreach end#如果對方需要加自己到對話清單裡面if($add){#debug#var_dump($toId."要加".$myId."(msgId為".$this->connInfo[$myId]["msgId"].")到通話清單裡面");#讓通話對象也可以傳送訊息回來$this->connInfo[$toId]["talkTo"][]=array("id"=>$myId,"userId"=>$myUserId,"msgId"=>$this->connInfo[$myId]["msgId"]);}#if end}#if end}#if end}#foreach end#移除留言紀錄unset($this->unSendMsg[$index]);}#if end}#foreach end#檢查線上是否有人想跟我對話#有幾個人在線上就執行幾次foreach($this->connInfo as $toId => $cInfo){#如果是自己if($myId===$toId){#跳過continue;}#if end#該cliet目前再跟幾個人通話,就執行幾次foreach($cInfo["talkTo"] as $tIndex=>$tInfo){#如果自己的userId在對方的對話清單裡面if($myUserId===$tInfo["userId"]){#假設自己需要被對方加到對話清單裡面$add=true;#檢查自己是否已經在對方的對話清單裡面#對方有幾個通話對象就執行幾次foreach($this->connInfo[$toId]["talkTo"] as $toIndex=>$toCinfo){#如果自己已經在對方的對話清單裡面if($myUserId===$toCinfo["userId"] && $myId===$toCinfo["id"]){#設置自己不需要被對方加到對話清單裡面$add=false;#跳出迴圈break;}#if end}#foreach end#另存針對自己userId的連線id$oneIdOfMyUserid=$this->connInfo[$toId]["talkTo"][$tIndex]["id"];#如果對方對話清單裡面的用戶id不在線if(!isset($this->connInfo[$oneIdOfMyUserid])){#假設要將自己在對方對話清單裡面的id改成現在的id$update=true;#自己不需要被對方加到對話清單裡面$add=false;#檢查自己的id是否已經在對方的對話id裡面foreach($this->connInfo[$toId]["talkTo"] as $ceIndex=>$ceInfo){#如果自己的id已經在對方的對話清單裡面if($myId===$ceInfo["id"]){#設置不要將自己在對方對話清單裡面的id改成現在的id(可以移除該對話id)$update=false;#跳出迴圈break;}#if end}#foreach end#如果要將自己在對方對話清單裡面的id改成現在的idif($update){#debug#var_dump($toId."要更新對話清單中索引為".$tIndex."的id(".$this->connInfo[$toId]["talkTo"][$tIndex]["id"].")為".$myId);#將自己在對方對話清單裡面的id改成現在的id$this->connInfo[$toId]["talkTo"][$tIndex]["id"]=$myId;}#if end#反之不要將自己在對方對話清單裡面的id改成現在的id(可以移除該對話id)else{#移除該對話idunset($this->connInfo[$toId]["talkTo"][$tIndex]);}#else end}#if end#如果要將自己加到對方的的通話清單裡面if($add){#debug#var_dump($toId."要加".$myId."(msgId為".$this->connInfo[$myId]["msgId"].")到通話清單裡面");#將自己加到對方的的通話清單裡面$this->connInfo[$toId]["talkTo"][]=array("id"=>$myId,"userId"=>$myUserId,"msgId"=>$this->connInfo[$myId]["msgId"]);}#if end#檢查對方是否已經在自己的對話清單裡面#設置要新增對方到自己的對話清單裡面.$add=true;#自己有幾個對話對象就執行幾次foreach($this->connInfo[$myId]["talkTo"] as $mtIndex=>$mtInfo){#對方的userId與id若在自己的對話清單裡面if($mtInfo["userId"]===$cInfo["userId"] && $mtInfo["id"]===$toId){#設置不需要新增對方到自己的對話清單裡面$add=false;#跳出 foreachbreak;}#if end}#foreache end#如果要新增對方到自己的對話清單裡面.if($add){#自己有幾個對話對象就執行幾次foreach($this->connInfo[$myId]["talkTo"] as $mtIndex=>$mtInfo){#如果對方已經在自己的通話清單if($mtInfo["userId"]===$cInfo["userId"] && $mtInfo["id"]===$toId){#設置不要將對方到自己的對話清單裡面.$add=false;#跳出 foreach endbreak;}#if end}#foreach end#如果要新增對方到自己的對話清單裡面.if($add){#將對方加到自己的對話清單裡面$this->connInfo[$myId]["talkTo"][]=array("id"=>$toId,"userId"=>$cInfo["userId"],"msgId"=>$this->connInfo[$toId]["msgId"]);}#if end}#if end}#if end}#foreach end}#foreach end#結束認證成功後的流程return true;}#else end}#else end#結束認證流程return true;}#if end#如果收到 "id?"else if($msg==="id?"){#包裝訊息#"type"為"id?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"id?","status"=>"true","data"=>$from->resourceId);#傳自己的id給client$from->send(json_encode($packedMsg));#回傳成功return true;}#if end#如果收到 "ids?"else if($msg==="ids?"){#初始化儲存其他人的id$idsArray=array();#針對所的clientforeach ($this->clients as $client){#排除自己if($from !== $client){#取得其他人的id$idsArray[]=$client->resourceId;}#if end}#foreach end#包裝訊息#"type"為"ids?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"ids?","status"=>"true","data"=>$idsArray);#傳他人的id給client$from->send(json_encode($packedMsg));#回傳成功return true;}#if end#如果收到 "talkTo?"else if($msg==="talkTo?"){#包裝訊息#"type"為"talkTo?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"talkTo?","status"=>"true","data"=>$this->connInfo[$from->resourceId]["talkTo"]);#正在對話的對象id給client$from->send(json_encode($packedMsg));#回傳成功return true;}#if end#反之如果是 "msgId?"else if($msg==="msgId?"){#包裝訊息#"type"為"talkTo?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"msgId?","status"=>"true","data"=>$this->connInfo[$from->resourceId]["msgId"]);#取得自己的msgId$from->send(json_encode($packedMsg));#回傳成功return true;}#if end#如果收到的$msg長度大於 "talkTo:"if(strlen($msg)>strlen("talkTo:")){#如果收到開頭為 "talkTo:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="talkTo:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "talkTo:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "talkTo:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "talkTo:" 分割 $buf#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="talkTo:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果剛好分割出一筆資料if($spiltString["dataCounts"]===1){#取得自己的id$myId=$from->resourceId;#取得講話對象的id$toId=$spiltString["dataArray"][0];#設置對象不存在的識別$targetExist=false;#設置通話對象的key$targetKey="";#如果要對話的對象存在if(isset($this->connInfo[$toId])){#取得對象的userId$toUserId=$this->connInfo[$toId]["userId"];#取得同userId的對象id們#初始化同userId的對象id$targetC=array();#針對每個連線foreach($this->connInfo as $eachIndex=>$eachInfo){#如果是自己if($eachIndex===$myId){#跳到下一輪continue;}#if end#如果是同userId的對象if($eachInfo["userId"]===$toUserId){#取出連線$targetC[$eachIndex]=$this->connInfo[$eachIndex];}#if end}#foreach end#針對每個同userId的連線foreach($targetC as $tcIndex=>$tcInfo){#檢查自己的對話對象是否已經在清單裡面了#假設對象可以加到自己對話清單裡面$add=true;#針對每個要講話的對象foreach($this->connInfo[$myId]["talkTo"] as $index=>$cInfo){#如果對話對象已經在清單裡面了if($this->connInfo[$tcIndex]["userId"]===$cInfo["userId"] && $tcIndex===$cInfo["id"] && $tcInfo["msgId"]===$cInfo["msgId"]){#設置不要再加到清單裡面$add=false;#跳出foreachbreak;}#if end}#foreach end#如果要加入到對話清單裡面if($add){#增加自己的對話對象$this->connInfo[$myId]["talkTo"][]=array("id"=>$tcIndex,"userId"=>$this->connInfo[$tcIndex]["userId"],"msgId"=>$this->connInfo[$tcIndex]["msgId"]);#假設對方可以加自己到對話清單裡面$add=true;#檢查通話對象能否跟自己對話foreach($this->connInfo[$tcIndex]["talkTo"] as $index=>$cInfo){#如果對話對象已經在清單裡面了if($this->connInfo[$myId]["userId"]===$cInfo["userId"]){#設置不要再加到清單裡面$add=false;#跳出 foreachbreak;}#if end}#foreach end#如果對方可以加自己到對話清單裡面if($add){#讓通話對象也可以傳送訊息回來$this->connInfo[$tcIndex]["talkTo"][]=array("id"=>$myId,"userId"=>$this->connInfo[$myId]["userId"],"msgId"=>$this->connInfo[$myId]["msgId"]);}#if end#設置成功訊息$msg="client id ".$toId." added to talkTo list";#包裝訊息#"type"為"status"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"true","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));}#if end#反之else{#設置錯誤訊息$msg="client id ".$toId." already in talkTo list";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));}#else end}#foreach end#回傳成功return true;}#if end#反之不存在else{#設置錯誤訊息$msg="client id ".$toId." doesn't exist";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));#回傳成功return true;}#else end}#if end}#if end}#if end#預設沒有收到確認收到訊息的回應訊息$mIndex="false";#如果收到的$msg長度大於 "msgId:"if(strlen($msg)>strlen("msgId:")){#解析 $msg#如果收到開頭為 "msgId:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="msgId:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "msgId:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "msgId:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "msgId:" 分割 $msg#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="msgId:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果剛好分割出一筆資料if($spiltString["dataCounts"]===1){#如果尚未設置過msgIdif($this->connInfo[$from->resourceId]["gotMsgId"]==="false"){#取得待確認訊息id$msgId=$spiltString["dataArray"][0];#初始化儲存現有msgId的變數$msgIdArray=array();#取得現有的msgIdforeach($this->connInfo as $cInfo){#如果msgId不為空if($cInfo["msgId"]!==""){#儲存msgId$msgIdArray[]=$cInfo["msgId"];}#if end}#foreach end#檢查msgId是否存在於$msgIdArray裡面if(in_array($msgId,$msgIdArray)){#設置自己的msgId$this->connInfo[$from->resourceId]["msgId"]=$msgId;#設置已經設置過msgId$this->connInfo[$from->resourceId]["gotMsgId"]="true";#設置成功訊息$msg="set msgId successfully";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"true","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));#針對每個連線foreach($this->connInfo as $connIndex=>$connInfo){#如果是跟發訊息者同msgId但id不一樣的連線if($connInfo["msgId"]===$msgId && $connIndex!==$from->resourceId){#將id為$connIndex的連線斷線$this->clients->detach($this->connInfo[$connIndex]["conn"]);#提示已經將連線斷開echo "Connection {$connIndex} has disconnected\n";#移除先前同msgId但id不一樣的連線unset($this->connInfo[$connIndex]);#針對每個連線foreach($this->connInfo as $cIndexForTD=>$cInfoForTD){#針對 talkTo 的每個項目foreach($cInfoForTD["talkTo"] as $ttIndex=>$ttInfo){#如果是不存在的通話對象if($ttInfo["id"]===$connIndex){#移除之unset($this->connInfo[$cIndexForTD]["talkTo"][$ttIndex]);}#if end}#foreach end}#foreach end}#if end}#foreach end#如果有要確認的訊息陣列if(isset($this->unConfirmMsg[$msgId])){#初始化要傳送的待確認訊息$packedMsg=array();#有幾個要確認的訊息就執行幾次foreach($this->unConfirmMsg[$msgId] as $unCMindex=>$unCMinfo){#如果待確認訊息的傳送目標id不等於剛要求更換msgId的用戶idif($unCMinfo["toId"]!==$from->resourceId){#設置傳送目標id為要求更換msgId的用戶id$this->unConfirmMsg[$msgId][$unCMindex]["toId"]=$from->resourceId;#檢查所有連線資訊foreach($this->connInfo as $connId=>$connInfo){#依據talkTo清單的每個對象foreach($connInfo["talkTo"] as $talk2Index=>$talk2Info){#若對象的id為$unCMinfo["toId"]且userId為$this->connInfo[$from->resourceId]["userId"]且msgId為$this->connInfo[$from->resourceId]["msgId"]者if($talk2Info["id"]===$unCMinfo["toId"] && $talk2Info["userId"]===$this->connInfo[$from->resourceId]["userId"] && $talk2Info["msgId"]===$this->connInfo[$from->resourceId]["msgId"]){#移除該talkTo對象unset($this->connInfo[$connId]["talkTo"][$talk2Index]);}#if ded}#foreach end}#foreach end}#if end#如果要傳送的待確認訊息為空陣列if($packedMsg===array()){#包裝訊息#"type"為"msg"#"index"為$cInfo["id"]#"data"為實際的訊息內容$packedMsg=array("type"=>"msg","index"=>$unCMindex,"data"=>$unCMinfo["msg"]);}#if end}#foreach end#如果要傳送的待確認訊息不為空陣列if($packedMsg!==array()){#var_dump("重新登入更改msgId後要傳送的未確認訊息:".print_r($packedMsg,true));#傳送包裝好的待確認訊息給對方$from->send(json_encode($packedMsg));}#if end}#if end#結束程式return true;}#if end}#if end#反之已經設置過 msgId 了else{#設置錯誤訊息$msg="msgId already set";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#設置失敗訊息$msg="set msgId failed";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));#結束程式return true;}#if end}#if end#如果訊息長度大於 strlen("mIndex:")if(strlen($msg)>strlen("mIndex:")){#如果是確認收到訊息的回應訊息開頭 "mIndex:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="mIndex:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "mIndex:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "mIndex:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "mIndex:" 分割 $buf#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="mIndex:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果存在分割的識別字串if($spiltString["found"]==="true"){#如果只分割出一段if($spiltString["dataCounts"]===1){#取得待確認訊息的索引$mIndex=$spiltString["dataArray"][0];}#if end}#if end}#if end}#if end#如果有要講話的對象if(count($this->connInfo[$from->resourceId]["talkTo"])>0){#依據每個對話對象foreach($this->connInfo[$from->resourceId]["talkTo"] as $index => $cInfo){#如果要講話的對象不存在(socket已經斷開)if(!isset($this->connInfo[$cInfo["id"]])){#將訊息儲存起來,等對象上線後再把訊息傳過去.$this->unSendMsg[]=array("fromId"=>$from->resourceId,"toId"=>"","fromUserId"=>$this->connInfo[$from->resourceId]["userId"],"toUserId"=>$cInfo["userId"],"msg"=>$msg);}#if end#反之,講話的對象存在else{#如果收到確認收到訊息的回應if($mIndex!=="false"){#儲存對話目標的msgId$targetMsgId=$this->connInfo[$from->resourceId]["msgId"];#針對每個連線的待確認訊息foreach($this->unConfirmMsg as $unCMindex=>$unCMinfo){#debug#var_dump($unCMindex."!==".$targetMsgId." && count(\$unCMinfo):".count($unCMinfo));#如果 未確認訊息達到10則以上 且不是接收訊息者的msgIdif($unCMindex!==$targetMsgId && count($unCMinfo)>10){#代表接收訊息的用戶無法透過網路跟server溝通#提示 server 連線已結束echo "Connection {$unCMinfo["id"]} has disconnected\n";#將待驗證的訊息變成留言訊息#有幾個未確認訊息就執行幾次foreach($this->unConfirmMsg[$unCMindex] as $unConMsgIndex => $unConMsgInfo){#將訊息儲存起來,等對象上線後再把訊息傳過去.$this->unSendMsg[]=array("fromId"=>$unConMsgInfo["fromId"],"toId"=>"","fromUserId"=>$unConMsgInfo["fromUserId"],"toUserId"=>$unConMsgInfo["toUserId"],"msg"=>$unConMsgInfo["msg"]);}#foreach end#移除待驗證的訊息資訊unset($this->unConfirmMsg[$unCMindex]);#將client的連線斷開$this->clients->detach($this->connInfo[$unConMsgInfo["fromId"]]["conn"]);#移除連線的資訊unset($this->connInfo[$unConMsgInfo["fromId"]]);}#if end}#foreach end#存在收到訊息用戶id的待確認訊息if(isset($this->unConfirmMsg[$targetMsgId])){#如果該未確認訊息存在if(isset($this->unConfirmMsg[$targetMsgId][$mIndex])){#debug#var_dump("移除待確認的訊息".print_r($this->unConfirmMsg[$targetMsgId][$mIndex],true));#移除該確認訊息unset($this->unConfirmMsg[$targetMsgId][$mIndex]);#還剩下幾個待確認訊息就執行幾次foreach($this->unConfirmMsg[$targetMsgId] as $unCMindex=>$unCMinfo){#如果後面還有訊息if(isset($this->unConfirmMsg[$targetMsgId][$unCMindex+1])){#如果與下一份訊息的 fromUserId一樣, toUserId 一樣, fromId一樣, toId 不同, msg 一樣.if(($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromUserId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromUserId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["toUserId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toUserId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["toId"]!==$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["msg"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["msg"])){#卸除該筆重複的訊息unset($this->unConfirmMsg[$targetMsgId][$unCMindex]);#跳到下一則訊息continue;}#if end/*#debugelse{var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromUserId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromUserId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["toUserId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toUserId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["toId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["msg"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["msg"]);}#else end*/}#if end#包裝訊息#"type"為"msg"#"index"為$cInfo["id"]#"data"為實際的訊息內容$packedMsg=array("type"=>"msg","index"=>$unCMindex,"data"=>$unCMinfo["msg"]);#傳送包裝好的待確認訊息給對方$from->send(json_encode($packedMsg));#一次只送一則訊息break;}#foreach end}#if end}#if end}#if end#反之為要傳送的訊息else{#儲存對話目標的msgId$targetMsgId=$this->connInfo[$cInfo["id"]]["msgId"];#$unConfirmMsg[$msgId],為訊息接收方的$msgId,亦即收到訊息後,要跟server說有收到訊息者.#"fromId",訊息來源的id#"toId",訊息目的的id#"fromUserId",訊息來源的userId#"toUserId",訊息目標的userId#"msg",傳送的訊息#"msgId",訊息目標連線的msgId#儲存待確認傳送的訊息到 $unConfirmMsg$this->unConfirmMsg[$targetMsgId][]=array('fromId'=>$from->resourceId,'toId'=>$cInfo["id"],'fromUserId'=>$this->connInfo[$from->resourceId]["userId"],'toUserId'=>$cInfo["userId"],'msg'=>$msg,'msgId'=>$this->connInfo[$cInfo["id"]]["msgId"]);#var_dump($this->unConfirmMsg[$targetMsgId]);#如果未確認的訊息數量已經達到10則if(count($this->unConfirmMsg[$targetMsgId])>10){#代表用戶無法透過網路跟server溝通#提示 server 連線已結束echo "Connection {$cInfo["id"]} has disconnected\n";#將待驗證的訊息變成留言訊息#有幾個未確認訊息就執行幾次foreach($this->unConfirmMsg[$targetMsgId] as $unCMindex => $unCMinfo){#將訊息儲存起來,等對象上線後再把訊息傳過去.$this->unSendMsg[]=array("fromId"=>$unCMinfo["fromId"],"toId"=>"","fromUserId"=>$unCMinfo["fromUserId"],"toUserId"=>$unCMinfo["toUserId"],"msg"=>$unCMinfo["msg"]);}#foreach end#移除待驗證的訊息資訊unset($this->unConfirmMsg[$targetMsgId]);#將client的連線斷開$this->clients->detach($this->connInfo[$cInfo["id"]]["conn"]);#移除連線的資訊unset($this->connInfo[$cInfo["id"]]);}#if end#反之else{#裡面有幾個待確認的訊息就執行幾次foreach($this->unConfirmMsg[$targetMsgId] as $unCMindex=>$unCMinfo){#如果後面還有訊息if(isset($this->unConfirmMsg[$targetMsgId][$unCMindex+1])){#debug#var_dump($this->unConfirmMsg[$targetMsgId]);#如果與下一份訊息的 fromUserId一樣, toUserId 一樣, fromId一樣, toId 不同, msg 一樣.if(($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromUserId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromUserId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["toUserId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toUserId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["toId"]!==$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["msg"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["msg"])){#卸除該筆重複的訊息unset($this->unConfirmMsg[$targetMsgId][$unCMindex]);#跳到下一則訊息continue;}#if end/*#debugelse{var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["toUserId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toUserId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["toId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["msg"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["msg"]);}#else end*/}#if end#debug#var_dump("index:".$targetMsgId.print_r($this->unConfirmMsg[$targetMsgId],true));#另存 ConnectionInterface 物件$connObject=$this->connInfo[$cInfo["id"]]["conn"];#包裝訊息#"type"為"msg"#"index"為$cInfo["id"]#"data"為實際的訊息內容$packedMsg=array("type"=>"msg","index"=>$unCMindex,"data"=>$unCMinfo["msg"]);#傳送包裝好的訊息給對方$connObject->send(json_encode($packedMsg));#一次只送一則訊息break;}#foreach end}#else end}#else end}#else end}#foreach end}#if end#反之沒有講話的對象else{$msg="Message 「".$msg."」 will not be received by any one";#提示server訊息被拋棄echo $msg;#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));}#else end}#function onMessage end#當clinet的連線斷掉前public function onClose(ConnectionInterface $conn){// The connection is closed, remove it, as we can no longer send it messages$this->clients->detach($conn);#提示 server 連線已結束echo "Connection {$conn->resourceId} has disconnected\n";#取得斷線目標的待確認訊息id$msgId=$this->connInfo[$conn->resourceId]["msgId"];#移除目標id的待確認訊息unset($this->unConfirmMsg[$msgId]);#移除連線的資訊unset($this->connInfo[$conn->resourceId]);}#function onClose end#當出現錯誤時public function onError(ConnectionInterface $conn, \Exception $e){#提示出現連線錯誤echo "An error has occurred: {$e->getMessage()}\n";#關閉socket$conn->close();}#fucntion onError end}#class ChatV2 end#用 ChatV3 類別來實作 MessageComponentInterface 界面,#新增可以對Server下達command的功能#修正要設置的msgId不存在時不會回傳錯誤訊息且繼續執行的問題class ChatV3 implements MessageComponentInterface{#初始化儲存使用者資訊的陣列private $connInfo=array();#初始化儲存未傳送出去的留言訊息#"fromId",訊息來源的id#"toId",訊息目的的id#"fromUserId",訊息來源的userId#"toUserId",訊息目標的userId#"msg",傳送的訊息private $unSendMsg=array();#初始化儲存待確認是否送達到對方的訊息#$unConfirmMsg[$id],$id為訊息接收方,亦即收到訊息後,要跟server說有收到訊息者.#"fromId",訊息來源的id#"toId",訊息目的的id#"fromUserId",訊息來源的userId#"toUserId",訊息目標的userId#"msg",傳送的訊息private $unConfirmMsg=array();#初始化一開始尚未能夠連線到資料庫private static $dbTouchable=false;#初始化db的位置public static $dbAddress="localhost";#初始化連線db用的帳戶public static $dbAccount="root";#初始化連線的db名稱public static $dbName="test";#初始化連線db時用的密碼public static $dbPassword="";#初始化連線db的哪個資料表public static $memberTableName="member";#初始化登入時用來驗證帳號的資料表欄位名稱public static $accountCol="account";#初始化登入時用來驗證密碼的資料表欄位名稱,設為""代表不用密碼來認證public static $passwordCol="password";#初始化用來儲存 __FILE__ 內容的變數 fileArgupublic static $fileArgu=__FILE__;#建構子public function __construct(){#如果尚未可以上資料庫if(!(self::$dbTouchable)){#嘗試連線到目標資料庫.資料表#涵式說明:#一次取得資料庫、表的資料#回傳的結果#$result["status"],執行結果"true"為成功;"false"為執行失敗。#$result["error"],錯誤訊息陣列。#$result["function"],當前執行的漢書名稱.#$result["dataColumnName"],抓取的資料欄位名稱陣列.#$result["dataColumnName"][$i]代表第$i+1個欄位名稱#$result["dataContent"],爲資料的內容。#$result["dataContent"][$conf["WhereColumnName"][$i]][$dataSetNum]#$dataSetNum 爲第$dataSetNum+1筆資料#$conf["WhereColumnName"][$i] 爲第 $i+1 個欄位的名稱#$result["dataCount"],爲取得的資料筆數。#$result["sql"],執行的sql字串.#必填的參數:$conf["db::fastGetDbData"]["dbAddress"]=self::$dbAddress;#爲dbServer的位置。$conf["db::fastGetDbData"]["dbAccount"]=self::$dbAccount;#爲登入dbServer的帳號。$conf["db::fastGetDbData"]["dbName"]=self::$dbName;#爲要存取的資料庫名稱$conf["db::fastGetDbData"]["tableName"]=self::$memberTableName;#爲要存取的資料表名稱$conf["db::fastGetDbData"]["columnYouWant"]=array("id",self::$accountCol);#你想要的欄位!,若設為「array("*")」則代表全部欄位.#如果 $passwordCol 不為空if(self::$passwordCol!=""){#加上密碼欄位$conf["db::fastGetDbData"]["columnYouWant"][]=self::$passwordCol;}#if end#可省略的參數:$conf["db::fastGetDbData"]["dbPassword"]=self::$dbPassword;#爲要存取dbServer的密碼#$conf["db::fastGetDbData"]["WhereColumnName"]=array("account","password");#用於判斷語句的欄位項目陣列。#$conf["db::fastGetDbData"]["WhereColumnValue"]=array($ac,$pw);#用於判斷語句的欄位數值陣列,若與LIKE搭配,則可以在關鍵自字串的左右名加上「%」符號,這樣就可以搜尋具有該字串的內容。#$conf["WhereColumnCombine"]=array("");#用於判斷語句當中需要()起來的判斷式,須爲陣列值,"s"代表「(」,"e"代表「)」 ,若無則須設爲""。#$conf["WhereColumnOperator"]=array("");#用於判斷語句的比較符號陣列,可以用的符號有「"="、"!="、">"、"<"、"LIKE"、"NOT LIKE"」,預設都爲「=」。#$conf["WhereColumnAndOr"]=array("");#用於判斷語句條件之間成立的條件是AND還是OR,須爲陣列值。其數量應爲要判斷的欄位數量減一。#$conf["orderItem"]="";#爲排序的項目依據,若要用隨機抽樣,可以用"rand()",可省略。#$conf["ascORdesc"]="";#爲要低增還是遞減排序,asc爲遞增;desc爲遞減。#$conf["numberStart"]="0";#為從第幾筆開始讀取,預設為0,代筆第一筆。$conf["db::fastGetDbData"]["numLimit"]="1";#為要取幾筆資料,可以省略,省略則表示不限制數目。#$conf["groupBy"]=array("");#爲要以哪幾個欄爲作爲分羣的依據(欄位相同的數值僅會取出一筆)。#備註:#建議在查詢資料前,能夠檢查是否每個欄位都存在.$fastGetDbData=db::fastGetDbData($conf["db::fastGetDbData"]);unset($conf["db::fastGetDbData"]);#如果取得資料失敗if($fastGetDbData["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$fastGetDbData;#印出debug訊息var_dump($result);#結束程式exit;}#if end#連線成功,將self::dbTouchable設為trueself::$dbTouchable=true;}#if end$this->clients = new \SplObjectStorage;}#funciton __construct end#當用戶與伺服器建立連線時public function onOpen(ConnectionInterface $conn){// Store the new connection to send messages to later$this->clients->attach($conn);#提示server有clent連上web socket.echo "New connection! ({$conn->resourceId})\n";#用client的id為index來儲存額外的資訊#元素 "conn" 代表已經建立連線的ConnectionInterface物件#元素 "talkTo" 代表要跟誰講話#元素 "userId" 代表辨識使用者的id#元素 "loigin=array("ac","pw")" 代表client輸入的帳號與密碼#元素 "msgId" 為用來識別待確認訊息的索引#元素 "gotMsgId" 為用來識別是否已經設置過 msgId 了#$this->connInfo[$conn->resourceId]=array("conn"=>$conn,"talkTo"=>array(),"userId"=>"","login"=>array("ac"=>"","pw"=>""),"type"=>"");$this->connInfo[$conn->resourceId]=array("conn"=>$conn,"talkTo"=>array(),"userId"=>"","login"=>array("ac"=>"","pw"=>""),"msgId"=>"","gotMsgId"=>"false");#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your account! ex:account:ws1");#提示輸入帳號$conn->send(json_encode($packedMsg));}#function onOpen end#當伺服器收到訊息時public function onMessage(ConnectionInterface $from, $msg){#debug#$array=array("msgId"=>$this->connInfo[$from->resourceId]["msgId"],"resourceId"=>$from->resourceId,"msg"=>$msg);#var_dump($array);#如果該連線沒有使用者idif($this->connInfo[$from->resourceId]["userId"]===""){#代表需要認證,認證的會員資料表 slef::memberTableName,需要以下三個欄位.#id 自訂#account 自訂#password varchar(33)/*#如果尚未輸入用戶端類型if($this->connInfo[$from->resourceId]["type"]===""){#如果 $msg 長度大於 "type:"if(strlen($msg) > strlen("type:")){#檢查有無前置字元 "account:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="type:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存用戶端類型$this->connInfo[$from->resourceId]["type"]=$delStrBeforeKeyWord["content"];}#if end#反之else{#提示輸入用戶端類型$from->send(json_encode("Please input your type! ex:type:user"));#結束程式return true;}#else end}#if end#反之代表輸入錯誤格式的typeelse{#提示輸入用戶端類型$from->send(json_encode("Please input your type! ex:type:user"));#結束程式return true;}#else end}#if end#如果用戶端是"user"if($this->connInfo[$from->resourceId]["type"]==="user"){#...}#if end#反之如果用戶端是"device"else if($this->connInfo[$from->resourceId]["type"]==="device"){#...}#if end*/#如果尚未輸入帳戶if($this->connInfo[$from->resourceId]["login"]["ac"]===""){#如果 $msg 長度大於 "account:"if(strlen($msg) > strlen("account:")){#檢查有無前置字元 "account:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="account:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存帳戶$this->connInfo[$from->resourceId]["login"]["ac"]=$delStrBeforeKeyWord["content"];}#if end#反之代表格式錯誤else{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your account! ex:account:ws1");#提示輸入帳號$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#反之代表輸入錯誤格式的accountelse{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your account! ex:account:ws1");#提示輸入帳號$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#如果有設置密碼欄位if(self::$passwordCol!==""){#如果尚未輸入密碼if($this->connInfo[$from->resourceId]["login"]["pw"]===""){#$msg 長度大於 "password:"if(strlen($msg) > strlen("password:")){#檢查有無前置字元 "password:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="password:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存密碼$this->connInfo[$from->resourceId]["login"]["pw"]=$delStrBeforeKeyWord["content"];}#if end#反之代表格式錯誤else{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your password! ex:password:ws1");#提示輸入密碼$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#反之代表格式錯誤else{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your password! ex:password:ws1");#提示輸入密碼$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end}#if end#如果已經輸入帳號了if($this->connInfo[$from->resourceId]["login"]["ac"]!=""){#設置可以進行驗證$startAuth=true;#另存帳號$ac=$this->connInfo[$from->resourceId]["login"]["ac"];#初始化密碼$pw="";#如果有設置密碼欄位if(self::$passwordCol!==""){#如果client已經輸入密碼了if($this->connInfo[$from->resourceId]["login"]["pw"]!=""){#另存密碼$pw=md5($this->connInfo[$from->resourceId]["login"]["pw"]);}#if end#反之else{#設置尚不能進行認證$startAuth=false;}#else end}#if end#如果尚不能進行驗證if(!$startAuth){#結束程式return true;}#if end#檢查有無符合的帳戶密碼#涵式說明:#一次取得資料庫、表的資料#回傳的結果#$result["status"],執行結果"true"為成功;"false"為執行失敗。#$result["error"],錯誤訊息陣列。#$result["function"],當前執行的漢書名稱.#$result["dataColumnName"],抓取的資料欄位名稱陣列.#$result["dataColumnName"][$i]代表第$i+1個欄位名稱#$result["dataContent"],爲資料的內容。#$result["dataContent"][$conf["WhereColumnName"][$i]][$dataSetNum]#$dataSetNum 爲第$dataSetNum+1筆資料#$conf["WhereColumnName"][$i] 爲第 $i+1 個欄位的名稱#$result["dataCount"],爲取得的資料筆數。#$result["sql"],執行的sql字串.#必填的參數:$conf["db::fastGetDbData"]["dbAddress"]=self::$dbAddress;#爲dbServer的位置。$conf["db::fastGetDbData"]["dbAccount"]=self::$dbAccount;#爲登入dbServer的帳號。$conf["db::fastGetDbData"]["dbName"]=self::$dbName;#爲要存取的資料庫名稱$conf["db::fastGetDbData"]["tableName"]=self::$memberTableName;#爲要存取的資料表名稱$conf["db::fastGetDbData"]["columnYouWant"]=array("id");#你想要的欄位!,若設為「array("*")」則代表全部欄位.#可省略的參數:$conf["db::fastGetDbData"]["dbPassword"]=self::$dbPassword;#爲要存取dbServer的密碼$conf["db::fastGetDbData"]["WhereColumnName"]=array(self::$accountCol);#用於判斷語句的欄位項目陣列。$conf["db::fastGetDbData"]["WhereColumnValue"]=array($ac);#用於判斷語句的欄位數值陣列,若與LIKE搭配,則可以在關鍵自字串的左右名加上「%」符號,這樣就可以搜尋具有該字串的內容。#如果有輸入密碼if($pw!==""){#新增要判斷 self::$password 欄位,是否有於 $pw$conf["db::fastGetDbData"]["WhereColumnName"][]=self::$passwordCol;$conf["db::fastGetDbData"]["WhereColumnValue"][]=$pw;}#if end#$conf["WhereColumnCombine"]=array("");#用於判斷語句當中需要()起來的判斷式,須爲陣列值,"s"代表「(」,"e"代表「)」 ,若無則須設爲""。#$conf["WhereColumnOperator"]=array("");#用於判斷語句的比較符號陣列,可以用的符號有「"="、"!="、">"、"<"、"LIKE"、"NOT LIKE"」,預設都爲「=」。#$conf["WhereColumnAndOr"]=array("");#用於判斷語句條件之間成立的條件是AND還是OR,須爲陣列值。其數量應爲要判斷的欄位數量減一。#$conf["orderItem"]="";#爲排序的項目依據,若要用隨機抽樣,可以用"rand()",可省略。#$conf["ascORdesc"]="";#爲要低增還是遞減排序,asc爲遞增;desc爲遞減。#$conf["numberStart"]="0";#為從第幾筆開始讀取,預設為0,代筆第一筆。$conf["db::fastGetDbData"]["numLimit"]="1";#為要取幾筆資料,可以省略,省略則表示不限制數目。#$conf["groupBy"]=array("");#爲要以哪幾個欄爲作爲分羣的依據(欄位相同的數值僅會取出一筆)。#備註:#建議在查詢資料前,能夠檢查是否每個欄位都存在.$fastGetDbData=db::fastGetDbData($conf["db::fastGetDbData"]);unset($conf["db::fastGetDbData"]);#如果取得資料失敗if($fastGetDbData["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$fastGetDbData;#提示server有資料庫錯誤echo "dbError!";#結束程式exit;}#if end#如果沒有一筆資料if($fastGetDbData["dataCount"]!==1){#代表登入失敗#清空登入用的帳戶$this->connInfo[$from->resourceId]["login"]["ac"]="";#清空登入用的密碼$this->connInfo[$from->resourceId]["login"]["pw"]="";#包裝訊息#"type"為"login"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"false","data"=>"Login failed, please input account. ex:account:ws1");#提示登入失敗$from->send(json_encode($packedMsg));#執行到這即可return true;}#if end#反之代表帳戶資訊正確else{#設置 $myUserId$myUserId=$this->connInfo[$from->resourceId]["userId"]=$fastGetDbData["dataContent"]["id"][0];#設置 $myId$myId=$from->resourceId;#初始化msgId的部份內容$msgId=$myUserId."-";#初始化儲存msgId的陣列$msgIdArray=array();#取得所有client的msgIdforeach($this->connInfo as $clientInfoArray){#如果msgId不為""if($clientInfoArray["msgId"]!==""){#取得msgId$msgIdArray[]=$clientInfoArray["msgId"];}#if end}#foreach end#如果尚未產生完整的msgId或msgId有重複while($msgId===$myUserId."-" || in_array($msgId,$msgIdArray)){#涵式說明:#建立以圖片(PNG格式)呈現的驗證碼.#回傳的解果:#$result["status"],執行是否正常,"true"代表執行成功,"false"代表執行失敗.#$result["error"],錯誤訊息.#$result["function"],檔前執行的函數名稱.#$result["randNumberWord"],傳驗證碼的內容.#$result["imgAddress"],圖片的位置與名稱.#必填的參數:#$conf["imgAddressAndName"],字串,爲驗證碼圖片儲存的位置與名稱,副檔名程式會自動產生$conf["authenticate::validationCode"]["imgAddressAndName"]="no used!";#$conf["fileArgu"],字串,php變數__FILE__的內容,亦即該檔案在檔案系統的絕對路徑$conf["authenticate::validationCode"]["fileArgu"]="no used!";#可省略的參數:#$conf["num"],字串,爲驗證碼的位數,請輸入阿拉伯數字,預設為"8"位數.#$conf["num"]="8";#$conf["disableImg"],字串,是否要取消驗證碼圖片的輸出,"true"為要取消,預設為"false"為不取消$conf["authenticate::validationCode"]["disableImg"]="true";#$conf["imgToData"],字串,預設為"true"代表將圖片轉存成base64圖片,並將原始圖片移除;反之為"false"#$conf["imgToData"]="true";$validationCode=authenticate::validationCode($conf["authenticate::validationCode"]);unset($conf["authenticate::validationCode"]);#如果產生亂數失敗if($validationCode["status"]==="false"){#設置錯誤狀態$result["status"]="false";#設置錯誤提示$result["error"]=$validationCode;#印出錯誤訊息var_dump($result);#回傳結果return $result;}#if end#儲存產生好的msgId$msgId=$myUserId."-".$validationCode["randNumberWord"];}#while end#設置獨立於id與userId且用於驗證訊息是否收到的msgId$this->connInfo[$from->resourceId]["msgId"]=$msgId;#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Login successfully!");#提示登入成功$from->send(json_encode($packedMsg));#檢查是否有訊息是要給自己的foreach($this->unSendMsg as $index => $historyMsg){#如果有要給自己的訊息if($myUserId===$historyMsg["toUserId"]){#包裝訊息#"type"為"unSendMsg?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"unSendMsg?","status"=>"true","data"=>$historyMsg["msg"]);#接收別人給的留言$from->send(json_encode($packedMsg));#有幾個人在線上就執行幾次foreach($this->connInfo as $toId => $cInfo){#如果是自己if($myId===$toId ){#跳過continue;}#if end#如果留言的對象有在線上if($historyMsg["fromUserId"]===$cInfo["userId"]){#檢查對方是否已經在自己的通話清單裡面了#初始化要將對方加到自己的對話清單裡面$add=false;#根據自己的每個通話對象foreach($this->connInfo[$myId]["talkTo"] as $myToIndex=>$myToCinfo ){#如果對對方已經存在於自己的對話清單裡面了if($myToCinfo["userId"]===$historyMsg["fromUserId"] && $myId===$historyMsg["fromId"]){#設置不要將對方加到自己的對話清單裡面$add=false;#跳出foreachbreak;}#if end}#foreach end#如果要將對方加到自己的對話清單裡面if($add){#將對方加到自己的talkTo清單裡面$this->connInfo[$myId]["talkTo"][]=array("id"=>$toId,"userId"=>$historyMsg["fromUserId"],"msgId"=>$this->connInfo[$toId]["msgId"]);}#if end#檢查自己有沒有在對方talkTo清單裡面#假設對方需要加自己到對話清單裡面$add=true;#檢查通話對象能否跟自己對話#依據對方每個通話的對象foreach($this->connInfo[$toId]["talkTo"] as $talkToIndex=>$talkToCinfo){#如果自己的userId已經在對方的對話清單裡面了if($myUserId===$talkToCinfo["userId"]){#如果對方對話userId對應的id不在線上if(!isset($this->connInfo[$toId])){#debug#var_dump("對方對話userId(".$talkToCinfo["userId"].")應的id(".$toId.")不在線上");#檢查對方對話清單是否已經含有自己的id與userId了#假設對方對話清單沒有自己的id與userId$update=true;#依據對方每個通話的對象foreach($this->connInfo[$toId]["talkTo"] as $ceToIndex=>$ceToCinfo){#如果對方對話清單已經含有自己的id與userId了if($ceToCinfo["id"]===$myId && $ceToCinfo["userId"]===$myUserId){#debug#var_dump("對方對話清單已經含有自己的id(".$myId.")與userId了(".$myUserId.")");#設置不需要更新$update=false;#debug#var_dump($toId."要加".$myId."到通話清單裡面");#設置對方不需要加自己到對話清單裡面$add=false;}#if end}#foreach end#如果對方對話清單沒有自己的id與userId與msgIdif($update){#debug#var_dump($toId."要更新對話清單中索引為".$talkToIndex."的id(".$this->connInfo[$toId]["talkTo"][$talkToIndex]["id"].")為".$myId);#將自己在對方對話清單裡面的id改成現在的id$this->connInfo[$toId]["talkTo"][$talkToIndex]["id"]=$myId;}#if end#反之對方對話清單已經有自己的id與userIdelse{#移除對方該已經斷線的對話idunset($this->connInfo[$toId]["talkTo"][$talkToIndex]);}#else end}#if end}#if end}#foreach end#如果對方需要加自己到對話清單裡面if($add){#檢查對方每個通話對象foreach($this->connInfo[$toId]["talkTo"] as $reCktIndex=>$reCktInfo){#如果已經有將自己加到對方的對話清單裡面if($reCktInfo["id"]===$myId && $reCktInfo["userId"]===$myUserId){#設置不用將自己加到對方的對話清單裡面$add=false;}#if end}#foreach end#如果對方需要加自己到對話清單裡面if($add){#debug#var_dump($toId."要加".$myId."(msgId為".$this->connInfo[$myId]["msgId"].")到通話清單裡面");#讓通話對象也可以傳送訊息回來$this->connInfo[$toId]["talkTo"][]=array("id"=>$myId,"userId"=>$myUserId,"msgId"=>$this->connInfo[$myId]["msgId"]);}#if end}#if end}#if end}#foreach end#移除留言紀錄unset($this->unSendMsg[$index]);}#if end}#foreach end#檢查線上是否有人想跟我對話#有幾個人在線上就執行幾次foreach($this->connInfo as $toId => $cInfo){#如果是自己if($myId===$toId){#跳過continue;}#if end#該cliet目前再跟幾個人通話,就執行幾次foreach($cInfo["talkTo"] as $tIndex=>$tInfo){#如果自己的userId在對方的對話清單裡面if($myUserId===$tInfo["userId"]){#假設自己需要被對方加到對話清單裡面$add=true;#檢查自己是否已經在對方的對話清單裡面#對方有幾個通話對象就執行幾次foreach($this->connInfo[$toId]["talkTo"] as $toIndex=>$toCinfo){#如果自己已經在對方的對話清單裡面if($myUserId===$toCinfo["userId"] && $myId===$toCinfo["id"]){#設置自己不需要被對方加到對話清單裡面$add=false;#跳出迴圈break;}#if end}#foreach end#另存針對自己userId的連線id$oneIdOfMyUserid=$this->connInfo[$toId]["talkTo"][$tIndex]["id"];#如果對方對話清單裡面的用戶id不在線if(!isset($this->connInfo[$oneIdOfMyUserid])){#假設要將自己在對方對話清單裡面的id改成現在的id$update=true;#自己不需要被對方加到對話清單裡面$add=false;#檢查自己的id是否已經在對方的對話id裡面foreach($this->connInfo[$toId]["talkTo"] as $ceIndex=>$ceInfo){#如果自己的id已經在對方的對話清單裡面if($myId===$ceInfo["id"]){#設置不要將自己在對方對話清單裡面的id改成現在的id(可以移除該對話id)$update=false;#跳出迴圈break;}#if end}#foreach end#如果要將自己在對方對話清單裡面的id改成現在的idif($update){#debug#var_dump($toId."要更新對話清單中索引為".$tIndex."的id(".$this->connInfo[$toId]["talkTo"][$tIndex]["id"].")為".$myId);#將自己在對方對話清單裡面的id改成現在的id$this->connInfo[$toId]["talkTo"][$tIndex]["id"]=$myId;}#if end#反之不要將自己在對方對話清單裡面的id改成現在的id(可以移除該對話id)else{#移除該對話idunset($this->connInfo[$toId]["talkTo"][$tIndex]);}#else end}#if end#如果要將自己加到對方的的通話清單裡面if($add){#debug#var_dump($toId."要加".$myId."(msgId為".$this->connInfo[$myId]["msgId"].")到通話清單裡面");#將自己加到對方的的通話清單裡面$this->connInfo[$toId]["talkTo"][]=array("id"=>$myId,"userId"=>$myUserId,"msgId"=>$this->connInfo[$myId]["msgId"]);}#if end#檢查對方是否已經在自己的對話清單裡面#設置要新增對方到自己的對話清單裡面.$add=true;#自己有幾個對話對象就執行幾次foreach($this->connInfo[$myId]["talkTo"] as $mtIndex=>$mtInfo){#對方的userId與id若在自己的對話清單裡面if($mtInfo["userId"]===$cInfo["userId"] && $mtInfo["id"]===$toId){#設置不需要新增對方到自己的對話清單裡面$add=false;#跳出 foreachbreak;}#if end}#foreache end#如果要新增對方到自己的對話清單裡面.if($add){#自己有幾個對話對象就執行幾次foreach($this->connInfo[$myId]["talkTo"] as $mtIndex=>$mtInfo){#如果對方已經在自己的通話清單if($mtInfo["userId"]===$cInfo["userId"] && $mtInfo["id"]===$toId){#設置不要將對方到自己的對話清單裡面.$add=false;#跳出 foreach endbreak;}#if end}#foreach end#如果要新增對方到自己的對話清單裡面.if($add){#將對方加到自己的對話清單裡面$this->connInfo[$myId]["talkTo"][]=array("id"=>$toId,"userId"=>$cInfo["userId"],"msgId"=>$this->connInfo[$toId]["msgId"]);}#if end}#if end}#if end}#foreach end}#foreach end#結束認證成功後的流程return true;}#else end}#else end#結束認證流程return true;}#if end#如果收到 "id?"else if($msg==="id?"){#包裝訊息#"type"為"id?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"id?","status"=>"true","data"=>$from->resourceId);#傳自己的id給client$from->send(json_encode($packedMsg));#回傳成功return true;}#if end#如果收到 "ids?"else if($msg==="ids?"){#初始化儲存其他人的id$idsArray=array();#針對所的clientforeach ($this->clients as $client){#排除自己if($from !== $client){#取得其他人的id$idsArray[]=$client->resourceId;}#if end}#foreach end#包裝訊息#"type"為"ids?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"ids?","status"=>"true","data"=>$idsArray);#傳他人的id給client$from->send(json_encode($packedMsg));#回傳成功return true;}#if end#如果收到 "talkTo?"else if($msg==="talkTo?"){#包裝訊息#"type"為"talkTo?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"talkTo?","status"=>"true","data"=>$this->connInfo[$from->resourceId]["talkTo"]);#正在對話的對象id給client$from->send(json_encode($packedMsg));#回傳成功return true;}#if end#反之如果是 "msgId?"else if($msg==="msgId?"){#包裝訊息#"type"為"talkTo?"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"msgId?","status"=>"true","data"=>$this->connInfo[$from->resourceId]["msgId"]);#取得自己的msgId$from->send(json_encode($packedMsg));#回傳成功return true;}#if end#如果收到的$msg長度大於 "talkTo:"if(strlen($msg)>strlen("talkTo:")){#如果收到開頭為 "talkTo:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="talkTo:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "talkTo:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "talkTo:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "talkTo:" 分割 $buf#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="talkTo:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果剛好分割出一筆資料if($spiltString["dataCounts"]===1){#取得自己的id$myId=$from->resourceId;#取得講話對象的id$toId=$spiltString["dataArray"][0];#設置對象不存在的識別$targetExist=false;#設置通話對象的key$targetKey="";#如果要對話的對象存在if(isset($this->connInfo[$toId])){#取得對象的userId$toUserId=$this->connInfo[$toId]["userId"];#取得同userId的對象id們#初始化同userId的對象id$targetC=array();#針對每個連線foreach($this->connInfo as $eachIndex=>$eachInfo){#如果是自己if($eachIndex===$myId){#跳到下一輪continue;}#if end#如果是同userId的對象if($eachInfo["userId"]===$toUserId){#取出連線$targetC[$eachIndex]=$this->connInfo[$eachIndex];}#if end}#foreach end#針對每個同userId的連線foreach($targetC as $tcIndex=>$tcInfo){#檢查自己的對話對象是否已經在清單裡面了#假設對象可以加到自己對話清單裡面$add=true;#針對每個要講話的對象foreach($this->connInfo[$myId]["talkTo"] as $index=>$cInfo){#如果對話對象已經在清單裡面了if($this->connInfo[$tcIndex]["userId"]===$cInfo["userId"] && $tcIndex===$cInfo["id"] && $tcInfo["msgId"]===$cInfo["msgId"]){#設置不要再加到清單裡面$add=false;#跳出foreachbreak;}#if end}#foreach end#如果要加入到對話清單裡面if($add){#增加自己的對話對象$this->connInfo[$myId]["talkTo"][]=array("id"=>$tcIndex,"userId"=>$this->connInfo[$tcIndex]["userId"],"msgId"=>$this->connInfo[$tcIndex]["msgId"]);#假設對方可以加自己到對話清單裡面$add=true;#檢查通話對象能否跟自己對話foreach($this->connInfo[$tcIndex]["talkTo"] as $index=>$cInfo){#如果對話對象已經在清單裡面了if($this->connInfo[$myId]["userId"]===$cInfo["userId"]){#設置不要再加到清單裡面$add=false;#跳出 foreachbreak;}#if end}#foreach end#如果對方可以加自己到對話清單裡面if($add){#讓通話對象也可以傳送訊息回來$this->connInfo[$tcIndex]["talkTo"][]=array("id"=>$myId,"userId"=>$this->connInfo[$myId]["userId"],"msgId"=>$this->connInfo[$myId]["msgId"]);}#if end#設置成功訊息$msg="client id ".$toId." added to talkTo list";#包裝訊息#"type"為"status"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"true","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));}#if end#反之else{#設置錯誤訊息$msg="client id ".$toId." already in talkTo list";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));}#else end}#foreach end#回傳成功return true;}#if end#反之不存在else{#設置錯誤訊息$msg="client id ".$toId." doesn't exist";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));#回傳成功return true;}#else end}#if end}#if end}#if end#預設沒有收到確認收到訊息的回應訊息$mIndex="false";#如果收到的$msg長度大於 "msgId:"if(strlen($msg)>strlen("msgId:")){#解析 $msg#如果收到開頭為 "msgId:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="msgId:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "msgId:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "msgId:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "msgId:" 分割 $msg#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="msgId:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果剛好分割出一筆資料if($spiltString["dataCounts"]===1){#如果尚未設置過msgIdif($this->connInfo[$from->resourceId]["gotMsgId"]==="false"){#取得待確認訊息id$msgId=$spiltString["dataArray"][0];#初始化儲存現有msgId的變數$msgIdArray=array();#取得現有的msgIdforeach($this->connInfo as $cInfo){#如果msgId不為空if($cInfo["msgId"]!==""){#儲存msgId$msgIdArray[]=$cInfo["msgId"];}#if end}#foreach end#檢查msgId是否存在於$msgIdArray裡面if(in_array($msgId,$msgIdArray)){#設置自己的msgId$this->connInfo[$from->resourceId]["msgId"]=$msgId;#設置已經設置過msgId$this->connInfo[$from->resourceId]["gotMsgId"]="true";#設置成功訊息$msg="set msgId successfully";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"true","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));#針對每個連線foreach($this->connInfo as $connIndex=>$connInfo){#如果是跟發訊息者同msgId但id不一樣的連線if($connInfo["msgId"]===$msgId && $connIndex!==$from->resourceId){#將id為$connIndex的連線斷線$this->clients->detach($this->connInfo[$connIndex]["conn"]);#提示已經將連線斷開echo "Connection {$connIndex} has disconnected\n";#移除先前同msgId但id不一樣的連線unset($this->connInfo[$connIndex]);#針對每個連線foreach($this->connInfo as $cIndexForTD=>$cInfoForTD){#針對 talkTo 的每個項目foreach($cInfoForTD["talkTo"] as $ttIndex=>$ttInfo){#如果是不存在的通話對象if($ttInfo["id"]===$connIndex){#移除之unset($this->connInfo[$cIndexForTD]["talkTo"][$ttIndex]);}#if end}#foreach end}#foreach end}#if end}#foreach end#如果有要確認的訊息陣列if(isset($this->unConfirmMsg[$msgId])){#初始化要傳送的待確認訊息$packedMsg=array();#有幾個要確認的訊息就執行幾次foreach($this->unConfirmMsg[$msgId] as $unCMindex=>$unCMinfo){#如果待確認訊息的傳送目標id不等於剛要求更換msgId的用戶idif($unCMinfo["toId"]!==$from->resourceId){#設置傳送目標id為要求更換msgId的用戶id$this->unConfirmMsg[$msgId][$unCMindex]["toId"]=$from->resourceId;#檢查所有連線資訊foreach($this->connInfo as $connId=>$connInfo){#依據talkTo清單的每個對象foreach($connInfo["talkTo"] as $talk2Index=>$talk2Info){#若對象的id為$unCMinfo["toId"]且userId為$this->connInfo[$from->resourceId]["userId"]且msgId為$this->connInfo[$from->resourceId]["msgId"]者if($talk2Info["id"]===$unCMinfo["toId"] && $talk2Info["userId"]===$this->connInfo[$from->resourceId]["userId"] && $talk2Info["msgId"]===$this->connInfo[$from->resourceId]["msgId"]){#移除該talkTo對象unset($this->connInfo[$connId]["talkTo"][$talk2Index]);}#if ded}#foreach end}#foreach end}#if end#如果要傳送的待確認訊息為空陣列if($packedMsg===array()){#包裝訊息#"type"為"msg"#"index"為$cInfo["id"]#"data"為實際的訊息內容$packedMsg=array("type"=>"msg","index"=>$unCMindex,"data"=>$unCMinfo["msg"]);}#if end}#foreach end#如果要傳送的待確認訊息不為空陣列if($packedMsg!==array()){#var_dump("重新登入更改msgId後要傳送的未確認訊息:".print_r($packedMsg,true));#傳送包裝好的待確認訊息給對方$from->send(json_encode($packedMsg));}#if end}#if end#結束程式return true;}#if end#反之想要用的msgId並不存在於serverelse{#設置錯誤訊息$msg="msgId 「".$msgId."」 doesn't exist";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#反之已經設置過 msgId 了else{#設置錯誤訊息$msg="msgId already set";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#設置失敗訊息$msg="set msgId failed";#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));#結束程式return true;}#if end}#if end#如果訊息長度大於 strlen("mIndex:")if(strlen($msg)>strlen("mIndex:")){#如果是確認收到訊息的回應訊息開頭 "mIndex:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="mIndex:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "mIndex:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "mIndex:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "mIndex:" 分割 $buf#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="mIndex:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果存在分割的識別字串if($spiltString["found"]==="true"){#如果只分割出一段if($spiltString["dataCounts"]===1){#取得待確認訊息的索引$mIndex=$spiltString["dataArray"][0];}#if end}#if end}#if end}#if end#如果server收到訊息長度大於 "cmd:"if(strlen($msg)>strlen("cmd:")){#如果$msg開頭為"cmd:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="cmd:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "cmd:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "cmd:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "cmd:" 分割 $buf#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="cmd:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果剛好分割出一筆資料if($spiltString["dataCounts"]===1){#取的要執行的指令$cmd=$spiltString["dataArray"][0];#函式說明:#呼叫shell執行系統命令,並取得回傳的內容.#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["function"],當前執行的函數名稱.#$result["cmd"],執行的指令內容.#$result["output"],爲執行完二元碼後的輸出陣列.#必填的參數#$conf["command"],字串,要執行的指令與.$conf["external::callShell"]["command"]=$cmd;#$conf["fileArgu"],字串,變數__FILE__的內容.$conf["external::callShell"]["fileArgu"]=self::$fileArgu;#可省略參數:#$conf["argu"],陣列字串,指令搭配的參數,預設為空陣列.#$conf["argu"]=array("");#$conf["arguIsAddr"],陣列字串,指令搭配的哪些參數為路徑,為路徑的參數會進行轉換以便符合呼叫當前函數的位置,預設不指定,若有3個參數,其中第3個參數為路徑,則表示為array("false","false","true").#$conf["arguIsAddr"]=array();#$conf["enablePrintDescription"],字串,是否要印出$conf["printDescription"]的內容,"true"代表要,"false"代表不要,預設為"false".#$conf["enablePrintDescription"]="true";#$conf["printDescription"],字串,執行該外部程式前要印出來的的文字,預設為$conf["command"]的內容.#$conf["printDescription"]="";#$conf["escapeshellarg"],字串,是否要啟用過濾參數,用了比較安全,但可能會出錯,"true"為啟用,"false"為不啟用,預設為"false".$conf["external::callShell"]["escapeshellarg"]="true";#$conf["username"],字串,要用什麼使用者來執行,預設為執行php的使用者,該參數不適用於apache環境.#$conf["username"]="";#$conf["password"],字串,與$conf["username"]搭配的使用者密碼,預設不使用密碼,該參數不適用於apache環境.#$conf["password"]="";#$conf["useScript"],字串,是否要啟用Linux的script指令來記錄輸出,"true"代表要;"false"代表不要,預設為"false".$conf["external::callShell"]["useScript"]="true";#$conf["logFilePath"],字串,當 $conf["useScript"] 為 "true" 時,輸出的內容要暫存到哪裡,預設為 ".qbpwcf_tmp/external/callShell/".#$conf["logFilePath"]=".qbpwcf_tmp/external/callShell/";#$conf["inBackGround"],字串,是否要在背景執行,且不會等待程式執行結束再執行下一個指令,"true"代表是,"false"代表不要,預設為"false",如果$conf["command"]有用「;」區隔的多個指令將會出錯.#$conf["inBackGround"]="";#備註:#不是所有指令都能用apache的身份執行,目前已知java,javac指令無法執行,使用root身份可能會被selinux阻擋.#參考資料:#exec=>http://php.net/manual/en/function.exec.php#escapeshellcmd=>http://php.net/manual/en/function.escapeshellcmd.php#escapeshellarg=>http://php.net/manual/en/function.escapeshellarg.php$callShell=external::callShell($conf["external::callShell"]);unset($conf["external::callShell"]);#如果執行外部指令失敗if($callShell["status"]==="false"){#設置要傳給client的訊息$result=array("data"=>$callShell,"type"=>"status","status"=>"false");#將程式執行後的錯誤輸出傳給client$from->send(json_encode($result));#回傳結果return true;}#if end#設置要傳給client的訊息$result=array("data"=>$callShell["output"],"type"=>"cmd");#將程式執行後的輸出傳給client$from->send(json_encode($result));#結束程式return true;}#if end}#if end}#if end#如果有要講話的對象if(count($this->connInfo[$from->resourceId]["talkTo"])>0){#依據每個對話對象foreach($this->connInfo[$from->resourceId]["talkTo"] as $index => $cInfo){#如果要講話的對象不存在(socket已經斷開)if(!isset($this->connInfo[$cInfo["id"]])){#將訊息儲存起來,等對象上線後再把訊息傳過去.$this->unSendMsg[]=array("fromId"=>$from->resourceId,"toId"=>"","fromUserId"=>$this->connInfo[$from->resourceId]["userId"],"toUserId"=>$cInfo["userId"],"msg"=>$msg);}#if end#反之,講話的對象存在else{#如果收到確認收到訊息的回應if($mIndex!=="false"){#儲存對話目標的msgId$targetMsgId=$this->connInfo[$from->resourceId]["msgId"];#針對每個連線的待確認訊息foreach($this->unConfirmMsg as $unCMindex=>$unCMinfo){#debug#var_dump($unCMindex."!==".$targetMsgId." && count(\$unCMinfo):".count($unCMinfo));#如果 未確認訊息達到10則以上 且不是接收訊息者的msgIdif($unCMindex!==$targetMsgId && count($unCMinfo)>10){#代表接收訊息的用戶無法透過網路跟server溝通#提示 server 連線已結束echo "Connection {$unCMinfo["id"]} has disconnected\n";#將待驗證的訊息變成留言訊息#有幾個未確認訊息就執行幾次foreach($this->unConfirmMsg[$unCMindex] as $unConMsgIndex => $unConMsgInfo){#將訊息儲存起來,等對象上線後再把訊息傳過去.$this->unSendMsg[]=array("fromId"=>$unConMsgInfo["fromId"],"toId"=>"","fromUserId"=>$unConMsgInfo["fromUserId"],"toUserId"=>$unConMsgInfo["toUserId"],"msg"=>$unConMsgInfo["msg"]);}#foreach end#移除待驗證的訊息資訊unset($this->unConfirmMsg[$unCMindex]);#將client的連線斷開$this->clients->detach($this->connInfo[$unConMsgInfo["fromId"]]["conn"]);#移除連線的資訊unset($this->connInfo[$unConMsgInfo["fromId"]]);}#if end}#foreach end#存在收到訊息用戶id的待確認訊息if(isset($this->unConfirmMsg[$targetMsgId])){#如果該未確認訊息存在if(isset($this->unConfirmMsg[$targetMsgId][$mIndex])){#debug#var_dump("移除待確認的訊息".print_r($this->unConfirmMsg[$targetMsgId][$mIndex],true));#移除該確認訊息unset($this->unConfirmMsg[$targetMsgId][$mIndex]);#還剩下幾個待確認訊息就執行幾次foreach($this->unConfirmMsg[$targetMsgId] as $unCMindex=>$unCMinfo){#如果後面還有訊息if(isset($this->unConfirmMsg[$targetMsgId][$unCMindex+1])){#如果與下一份訊息的 fromUserId一樣, toUserId 一樣, fromId一樣, toId 不同, msg 一樣.if(($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromUserId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromUserId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["toUserId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toUserId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["toId"]!==$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["msg"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["msg"])){#卸除該筆重複的訊息unset($this->unConfirmMsg[$targetMsgId][$unCMindex]);#跳到下一則訊息continue;}#if end/*#debugelse{var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromUserId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromUserId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["toUserId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toUserId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["toId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["msg"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["msg"]);}#else end*/}#if end#包裝訊息#"type"為"msg"#"index"為$cInfo["id"]#"data"為實際的訊息內容$packedMsg=array("type"=>"msg","index"=>$unCMindex,"data"=>$unCMinfo["msg"]);#傳送包裝好的待確認訊息給對方$from->send(json_encode($packedMsg));#一次只送一則訊息break;}#foreach end}#if end}#if end}#if end#反之為要傳送的訊息else{#儲存對話目標的msgId$targetMsgId=$this->connInfo[$cInfo["id"]]["msgId"];#$unConfirmMsg[$msgId],為訊息接收方的$msgId,亦即收到訊息後,要跟server說有收到訊息者.#"fromId",訊息來源的id#"toId",訊息目的的id#"fromUserId",訊息來源的userId#"toUserId",訊息目標的userId#"msg",傳送的訊息#"msgId",訊息目標連線的msgId#儲存待確認傳送的訊息到 $unConfirmMsg$this->unConfirmMsg[$targetMsgId][]=array('fromId'=>$from->resourceId,'toId'=>$cInfo["id"],'fromUserId'=>$this->connInfo[$from->resourceId]["userId"],'toUserId'=>$cInfo["userId"],'msg'=>$msg,'msgId'=>$this->connInfo[$cInfo["id"]]["msgId"]);#var_dump($this->unConfirmMsg[$targetMsgId]);#如果未確認的訊息數量已經達到10則if(count($this->unConfirmMsg[$targetMsgId])>10){#代表用戶無法透過網路跟server溝通#提示 server 連線已結束echo "Connection {$cInfo["id"]} has disconnected\n";#將待驗證的訊息變成留言訊息#有幾個未確認訊息就執行幾次foreach($this->unConfirmMsg[$targetMsgId] as $unCMindex => $unCMinfo){#將訊息儲存起來,等對象上線後再把訊息傳過去.$this->unSendMsg[]=array("fromId"=>$unCMinfo["fromId"],"toId"=>"","fromUserId"=>$unCMinfo["fromUserId"],"toUserId"=>$unCMinfo["toUserId"],"msg"=>$unCMinfo["msg"]);}#foreach end#移除待驗證的訊息資訊unset($this->unConfirmMsg[$targetMsgId]);#將client的連線斷開$this->clients->detach($this->connInfo[$cInfo["id"]]["conn"]);#移除連線的資訊unset($this->connInfo[$cInfo["id"]]);}#if end#反之else{#裡面有幾個待確認的訊息就執行幾次foreach($this->unConfirmMsg[$targetMsgId] as $unCMindex=>$unCMinfo){#如果後面還有訊息if(isset($this->unConfirmMsg[$targetMsgId][$unCMindex+1])){#debug#var_dump($this->unConfirmMsg[$targetMsgId]);#如果與下一份訊息的 fromUserId一樣, toUserId 一樣, fromId一樣, toId 不同, msg 一樣.if(($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromUserId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromUserId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["toUserId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toUserId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["fromId"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["fromId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["toId"]!==$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toId"])&&($this->unConfirmMsg[$targetMsgId][$unCMindex]["msg"]===$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["msg"])){#卸除該筆重複的訊息unset($this->unConfirmMsg[$targetMsgId][$unCMindex]);#跳到下一則訊息continue;}#if end/*#debugelse{var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["toUserId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toUserId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["toId"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["toId"]);var_dump($this->unConfirmMsg[$targetMsgId][$unCMindex]["msg"].":".$this->unConfirmMsg[$targetMsgId][$unCMindex+1]["msg"]);}#else end*/}#if end#debug#var_dump("index:".$targetMsgId.print_r($this->unConfirmMsg[$targetMsgId],true));#另存 ConnectionInterface 物件$connObject=$this->connInfo[$cInfo["id"]]["conn"];#包裝訊息#"type"為"msg"#"index"為$cInfo["id"]#"data"為實際的訊息內容$packedMsg=array("type"=>"msg","index"=>$unCMindex,"data"=>$unCMinfo["msg"]);#傳送包裝好的訊息給對方$connObject->send(json_encode($packedMsg));#一次只送一則訊息break;}#foreach end}#else end}#else end}#else end}#foreach end}#if end#反之沒有講話的對象else{$msg="Message 「".$msg."」 will not be received by any one";#提示server訊息被拋棄echo $msg;#包裝訊息#"type"為"status"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"status","status"=>"false","data"=>$msg);#設置要給自己看的訊息$from->send(json_encode($packedMsg));}#else end}#function onMessage end#當clinet的連線斷掉前public function onClose(ConnectionInterface $conn){// The connection is closed, remove it, as we can no longer send it messages$this->clients->detach($conn);#提示 server 連線已結束echo "Connection {$conn->resourceId} has disconnected\n";#取得斷線目標的待確認訊息id$msgId=$this->connInfo[$conn->resourceId]["msgId"];#移除目標id的待確認訊息unset($this->unConfirmMsg[$msgId]);#移除連線的資訊unset($this->connInfo[$conn->resourceId]);}#function onClose end#當出現錯誤時public function onError(ConnectionInterface $conn, \Exception $e){#提示出現連線錯誤echo "An error has occurred: {$e->getMessage()}\n";#關閉socket$conn->close();}#fucntion onError end}#class ChatV3 end#用 soldier 類別來實作 MessageComponentInterface 界面,提供驗證身份後就可以執行系統命令的界面.class soldier implements MessageComponentInterface{#初始化儲存使用者資訊的陣列private $connInfo=array();#初始化一開始尚未能夠連線到資料庫private static $dbTouchable=false;#初始化db的位置public static $dbAddress="localhost";#初始化連線db用的帳戶public static $dbAccount="root";#初始化連線的db名稱public static $dbName="test";#初始化連線db時用的密碼public static $dbPassword="";#初始化連線db的哪個資料表public static $memberTableName="member";#初始化登入時用來驗證帳號的資料表欄位名稱public static $accountCol="account";#初始化登入時用來驗證密碼的資料表欄位名稱,設為""代表不用密碼來認證public static $passwordCol="password";#初始化用來儲存 __FILE__ 內容的變數 fileArgupublic static $fileArgu=__FILE__;#當用戶與伺服器建立連線時public function onOpen(ConnectionInterface $conn){// Store the new connection to send messages to later$this->clients->attach($conn);#提示server有clent連上web socket.echo "New connection! ({$conn->resourceId})\n";#用client的id為index來儲存額外的資訊#元素 "conn" 代表已經建立連線的ConnectionInterface物件#元素 "talkTo" 代表要跟誰講話#元素 "userId" 代表辨識使用者的id#元素 "loigin=array("ac","pw")" 代表client輸入的帳號與密碼$this->connInfo[$conn->resourceId]=array("conn"=>$conn,"userId"=>"","login"=>array("ac"=>"","pw"=>""));#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your account! ex:account:ws1");#提示輸入帳號$conn->send(json_encode($packedMsg));}#function onOpen end#當伺服器收到訊息時public function onMessage(ConnectionInterface $from, $msg){#如果該連線沒有使用者idif($this->connInfo[$from->resourceId]["userId"]===""){#如果尚未輸入帳戶if($this->connInfo[$from->resourceId]["login"]["ac"]===""){#如果 $msg 長度大於 "account:"if(strlen($msg) > strlen("account:")){#檢查有無前置字元 "account:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="account:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存帳戶$this->connInfo[$from->resourceId]["login"]["ac"]=$delStrBeforeKeyWord["content"];}#if end#反之代表格式錯誤else{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your account! ex:account:ws1");#提示輸入帳號$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#反之代表輸入錯誤格式的accountelse{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your account! ex:account:ws1");#提示輸入帳號$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#如果有設置密碼欄位if(self::$passwordCol!==""){#如果尚未輸入密碼if($this->connInfo[$from->resourceId]["login"]["pw"]===""){#$msg 長度大於 "password:"if(strlen($msg) > strlen("password:")){#檢查有無前置字元 "password:"#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填的參數:$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$msg;#要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="password:";#特定字串.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果移除前置字元失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果有符合條件的前置字元if($delStrBeforeKeyWord["founded"]==="true"){#儲存密碼$this->connInfo[$from->resourceId]["login"]["pw"]=$delStrBeforeKeyWord["content"];}#if end#反之代表格式錯誤else{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your password! ex:password:ws1");#提示輸入密碼$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end#反之代表格式錯誤else{#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Please input your password! ex:password:ws1");#提示輸入密碼$from->send(json_encode($packedMsg));#結束程式return true;}#else end}#if end}#if end#如果已經輸入帳號了if($this->connInfo[$from->resourceId]["login"]["ac"]!=""){#設置可以進行驗證$startAuth=true;#另存帳號$ac=$this->connInfo[$from->resourceId]["login"]["ac"];#初始化密碼$pw="";#如果有設置密碼欄位if(self::$passwordCol!==""){#如果client已經輸入密碼了if($this->connInfo[$from->resourceId]["login"]["pw"]!=""){#取得密碼$pw=$this->connInfo[$from->resourceId]["login"]["pw"];}#if end#反之else{#設置尚不能進行認證$startAuth=false;}#else end}#if end#如果尚不能進行驗證if(!$startAuth){#結束程式return true;}#if end#檢查有無符合的帳戶密碼#涵式說明:#一次取得資料庫、表的資料#回傳的結果#$result["status"],執行結果"true"為成功;"false"為執行失敗。#$result["error"],錯誤訊息陣列。#$result["function"],當前執行的漢書名稱.#$result["dataColumnName"],抓取的資料欄位名稱陣列.#$result["dataColumnName"][$i]代表第$i+1個欄位名稱#$result["dataContent"],爲資料的內容。#$result["dataContent"][$conf["WhereColumnName"][$i]][$dataSetNum]#$dataSetNum 爲第$dataSetNum+1筆資料#$conf["WhereColumnName"][$i] 爲第 $i+1 個欄位的名稱#$result["dataCount"],爲取得的資料筆數。#$result["sql"],執行的sql字串.#必填的參數:$conf["db::fastGetDbData"]["dbAddress"]=self::$dbAddress;#爲dbServer的位置。$conf["db::fastGetDbData"]["dbAccount"]=self::$dbAccount;#爲登入dbServer的帳號。$conf["db::fastGetDbData"]["dbName"]=self::$dbName;#爲要存取的資料庫名稱$conf["db::fastGetDbData"]["tableName"]=self::$memberTableName;#爲要存取的資料表名稱$conf["db::fastGetDbData"]["columnYouWant"]=array("id","password");#你想要的欄位!,若設為「array("*")」則代表全部欄位.#可省略的參數:$conf["db::fastGetDbData"]["dbPassword"]=self::$dbPassword;#爲要存取dbServer的密碼$conf["db::fastGetDbData"]["WhereColumnName"]=array(self::$accountCol);#用於判斷語句的欄位項目陣列。$conf["db::fastGetDbData"]["WhereColumnValue"]=array($ac);#用於判斷語句的欄位數值陣列,若與LIKE搭配,則可以在關鍵自字串的左右名加上「%」符號,這樣就可以搜尋具有該字串的內容。/*#如果有輸入密碼if($pw!==""){#新增要判斷 self::$password 欄位,是否有於 $pw$conf["db::fastGetDbData"]["WhereColumnName"][]=self::$passwordCol;$conf["db::fastGetDbData"]["WhereColumnValue"][]=$pw;}#if end*/#$conf["WhereColumnCombine"]=array("");#用於判斷語句當中需要()起來的判斷式,須爲陣列值,"s"代表「(」,"e"代表「)」 ,若無則須設爲""。#$conf["WhereColumnOperator"]=array("");#用於判斷語句的比較符號陣列,可以用的符號有「"="、"!="、">"、"<"、"LIKE"、"NOT LIKE"」,預設都爲「=」。#$conf["WhereColumnAndOr"]=array("");#用於判斷語句條件之間成立的條件是AND還是OR,須爲陣列值。其數量應爲要判斷的欄位數量減一。#$conf["orderItem"]="";#爲排序的項目依據,若要用隨機抽樣,可以用"rand()",可省略。#$conf["ascORdesc"]="";#爲要低增還是遞減排序,asc爲遞增;desc爲遞減。#$conf["numberStart"]="0";#為從第幾筆開始讀取,預設為0,代筆第一筆。$conf["db::fastGetDbData"]["numLimit"]="1";#為要取幾筆資料,可以省略,省略則表示不限制數目。#$conf["groupBy"]=array("");#爲要以哪幾個欄爲作爲分羣的依據(欄位相同的數值僅會取出一筆)。#備註:#建議在查詢資料前,能夠檢查是否每個欄位都存在.$fastGetDbData=db::fastGetDbData($conf["db::fastGetDbData"]);unset($conf["db::fastGetDbData"]);#如果取得資料失敗if($fastGetDbData["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$fastGetDbData;#debug in servervar_dump($result);#提示server有資料庫錯誤echo "dbError!";#結束程式exit;}#if end#如果沒有一筆資料if($fastGetDbData["dataCount"]!==1){#代表登入失敗#清空登入用的帳戶$this->connInfo[$from->resourceId]["login"]["ac"]="";#清空登入用的密碼$this->connInfo[$from->resourceId]["login"]["pw"]="";#包裝訊息#"type"為"login"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"false","data"=>"Login failed, please input account. ex:account:ws1");#提示登入失敗$from->send(json_encode($packedMsg));#執行到這即可return true;}#if end#反之代表帳戶資訊正確else{#驗證密碼是否正確.#函式說明:#加密字串,可以用的方法有sha1,md5,password_sha,sha1可以回傳20或40的數值字串,md5可以回傳32個數值字串,password_hash可以回傳60~255個字元.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數名稱.#$result["content"],加密後的結果.#$result["error"],錯誤訊息陣列.#$result["argu"],使用的參數.#必填參數:#$conf["enCodeStr"],"字串",要加密的字串.$conf["authenticate::enCodeStr"]["enCodeStr"]=$pw;#$conf["enCodeType"],"字串",加密的類型,有"sha1"與"md5"與"p_hash"3種,"sha1"較耗時,"md5"較快,"p_hash"適用於密碼加密.$conf["authenticate::enCodeStr"]["enCodeType"]="p_hash";#可省略參數:#$conf["sha1Raw"],字串,sha1加密的結果要用20個0與1組合還是要用40位數的16進位數值,"true"代表前者,"false"代表後者,預設為"false".#$conf["sha1Raw"]="false";#$conf["p_hash"],字串,p_hash加密過後的字串,該參數若存在且$conf["enCodeType"]為"p_hash",則代表是要檢查$conf["enCodeStr"]是否為符合$conf["p_hash"]的密碼.$conf["authenticate::enCodeStr"]["p_hash"]=$fastGetDbData["dataContent"]["password"][0];#參考資料來源:#sha1=>http://php.net/manual/en/function.sha1.php#md5=>http://php.net/manual/en/function.md5.php#password_hash=>http://php.net/manual/en/function.password-hash.php#password_verify=>http://php.net/manual/en/function.password-verify.php$enCodeStr=authenticate::enCodeStr($conf["authenticate::enCodeStr"]);unset($conf["authenticate::enCodeStr"]);#如果加密密碼失敗if($enCodeStr["status"]==="false"){#debug from servervar_dump($enCodeStr);#提示server有資料庫錯誤echo "password verify error!";#代表登入失敗#清空登入用的帳戶$this->connInfo[$from->resourceId]["login"]["ac"]="";#清空登入用的密碼$this->connInfo[$from->resourceId]["login"]["pw"]="";#包裝訊息#"type"為"login"#"status"為"false"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"false","data"=>"Login failed, please input account. ex:account:ws1");#提示登入失敗$from->send(json_encode($packedMsg));#執行到這即可return true;}#if end#反之認證成功else{#debug for serverecho "new login:".PHP_EOL;var_dump($enCodeStr);}#else end#設置 $myUserId$myUserId=$this->connInfo[$from->resourceId]["userId"]=$fastGetDbData["dataContent"]["id"][0];#設置 $myId$myId=$from->resourceId;#包裝訊息#"type"為"login"#"status"為"true"#"data"為實際的訊息內容$packedMsg=array("type"=>"login","status"=>"true","data"=>"Login successfully!");#提示登入成功$from->send(json_encode($packedMsg));#結束認證成功後的流程return true;}#else end}#else end#結束認證流程return true;}#if end#如果server收到訊息長度大於 "cmd:"if(strlen($msg)>strlen("cmd:")){#如果$msg開頭為"cmd:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="cmd:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "cmd:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "cmd:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "talkTo:" 分割 $buf#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="cmd:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果剛好分割出一筆資料if($spiltString["dataCounts"]===1){#取的要執行的指令$cmd=$spiltString["dataArray"][0];#函式說明:#呼叫shell執行系統命令,並取得回傳的內容.#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["function"],當前執行的函數名稱.#$result["cmd"],執行的指令內容.#$result["output"],爲執行完二元碼後的輸出陣列.#必填的參數#$conf["command"],字串,要執行的指令與.$conf["external::callShell"]["command"]=$cmd;#$conf["fileArgu"],字串,變數__FILE__的內容.$conf["external::callShell"]["fileArgu"]=self::$fileArgu;#可省略參數:#$conf["argu"],陣列字串,指令搭配的參數,預設為空陣列.#$conf["argu"]=array("");#$conf["arguIsAddr"],陣列字串,指令搭配的哪些參數為路徑,為路徑的參數會進行轉換以便符合呼叫當前函數的位置,預設不指定,若有3個參數,其中第3個參數為路徑,則表示為array("false","false","true").#$conf["arguIsAddr"]=array();#$conf["enablePrintDescription"],字串,是否要印出$conf["printDescription"]的內容,"true"代表要,"false"代表不要,預設為"false".#$conf["enablePrintDescription"]="true";#$conf["printDescription"],字串,執行該外部程式前要印出來的的文字,預設為$conf["command"]的內容.#$conf["printDescription"]="";#$conf["escapeshellarg"],字串,是否要啟用過濾參數,用了比較安全,但可能會出錯,"true"為啟用,"false"為不啟用,預設為"false".$conf["external::callShell"]["escapeshellarg"]="true";#$conf["username"],字串,要用什麼使用者來執行,預設為執行php的使用者,該參數不適用於apache環境.#$conf["username"]="";#$conf["password"],字串,與$conf["username"]搭配的使用者密碼,預設不使用密碼,該參數不適用於apache環境.#$conf["password"]="";#$conf["useScript"],字串,是否要啟用Linux的script指令來記錄輸出,"true"代表要;"false"代表不要,預設為"false".#$conf["useScript"]="";#$conf["logFilePath"],字串,當 $conf["useScript"] 為 "true" 時,輸出的內容要暫存到哪裡,預設為 ".qbpwcf_tmp/external/callShell/".#$conf["logFilePath"]=".qbpwcf_tmp/external/callShell/";#$conf["inBackGround"],字串,是否要在背景執行,且不會等待程式執行結束再執行下一個指令,"true"代表是,"false"代表不要,預設為"false",如果$conf["command"]有用「;」區隔的多個指令將會出錯.#$conf["inBackGround"]="";#備註:#不是所有指令都能用apache的身份執行,目前已知java,javac指令無法執行,使用root身份可能會被selinux阻擋.#參考資料:#exec=>http://php.net/manual/en/function.exec.php#escapeshellcmd=>http://php.net/manual/en/function.escapeshellcmd.php#escapeshellarg=>http://php.net/manual/en/function.escapeshellarg.php$callShell=external::callShell($conf["external::callShell"]);unset($conf["external::callShell"]);#如果執行外部指令失敗if($callShell["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$callShell;#回傳結果return $result;}#if end#設置要傳給client的訊息$result=array("data"=>$callShell["output"],"type"=>"cmd");#將程式執行後的輸出傳給client$from->send(json_encode($result));}#if end}#if end}#if end#如果server收到訊息長度大於 "sql:"if(strlen($msg)>strlen("sql:")){#如果$msg開頭為"sql:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$msg;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="sql:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "sql:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "sql:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "talkTo:" 分割 $buf#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$msg;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="sql:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果剛好分割出一筆資料if($spiltString["dataCounts"]===1){#取的要執行的sql指令$sql=$spiltString["dataArray"][0];#建立要執行的指令#$cmd="echo \"".$sql."\" | mysql -u".self::$dbAccount." -p".self::$dbPassword;#函式說明:#呼叫shell執行系統命令,並取得回傳的內容.#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["function"],當前執行的函數名稱.#$result["cmd"],執行的指令內容.#$result["output"],爲執行完二元碼後的輸出陣列.#必填的參數#$conf["command"],字串,要執行的指令與.$conf["external::callShell"]["command"]="echo";#$conf["fileArgu"],字串,變數__FILE__的內容.$conf["external::callShell"]["fileArgu"]=self::$fileArgu;#可省略參數:#$conf["argu"],陣列字串,指令搭配的參數,預設為空陣列.$conf["external::callShell"]["argu"]=array($sql,"|","mysql","-u".self::$dbAccount,"-p".self::$dbPassword);#$conf["arguIsAddr"],陣列字串,指令搭配的哪些參數為路徑,為路徑的參數會進行轉換以便符合呼叫當前函數的位置,預設不指定,若有3個參數,其中第3個參數為路徑,則表示為array("false","false","true").#$conf["arguIsAddr"]=array();#$conf["enablePrintDescription"],字串,是否要印出$conf["printDescription"]的內容,"true"代表要,"false"代表不要,預設為"false".#$conf["enablePrintDescription"]="true";#$conf["printDescription"],字串,執行該外部程式前要印出來的的文字,預設為$conf["command"]的內容.#$conf["printDescription"]="";#$conf["escapeshellarg"],字串,是否要啟用過濾參數,用了比較安全,但可能會出錯,"true"為啟用,"false"為不啟用,預設為"false".$conf["external::callShell"]["escapeshellarg"]="true";#$conf["username"],字串,要用什麼使用者來執行,預設為執行php的使用者,該參數不適用於apache環境.#$conf["username"]="";#$conf["password"],字串,與$conf["username"]搭配的使用者密碼,預設不使用密碼,該參數不適用於apache環境.#$conf["password"]="";#$conf["useScript"],字串,是否要啟用Linux的script指令來記錄輸出,"true"代表要;"false"代表不要,預設為"false".#$conf["useScript"]="";#$conf["logFilePath"],字串,當 $conf["useScript"] 為 "true" 時,輸出的內容要暫存到哪裡,預設為 ".qbpwcf_tmp/external/callShell/".#$conf["logFilePath"]=".qbpwcf_tmp/external/callShell/";#$conf["inBackGround"],字串,是否要在背景執行,且不會等待程式執行結束再執行下一個指令,"true"代表是,"false"代表不要,預設為"false",如果$conf["command"]有用「;」區隔的多個指令將會出錯.#$conf["inBackGround"]="";#備註:#不是所有指令都能用apache的身份執行,目前已知java,javac指令無法執行,使用root身份可能會被selinux阻擋.#參考資料:#exec=>http://php.net/manual/en/function.exec.php#escapeshellcmd=>http://php.net/manual/en/function.escapeshellcmd.php#escapeshellarg=>http://php.net/manual/en/function.escapeshellarg.php$callShell=external::callShell($conf["external::callShell"]);unset($conf["external::callShell"]);#如果執行外部指令失敗if($callShell["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$callShell;#回傳結果return $result;}#if end#設置要傳給client的訊息$result=array("data"=>$callShell["output"],"type"=>"sql");#將程式執行後的輸出傳給client$from->send(json_encode($result));}#if end}#if end}#if end}#function onMessage end#建構子function __construct(){#實做 SplObjectStorage$this->clients = new \SplObjectStorage;}#function __construct end#在clinet的連線斷掉前public function onClose(ConnectionInterface $conn){// The connection is closed, remove it, as we can no longer send it messages$this->clients->detach($conn);echo "Connection {$conn->resourceId} has disconnected\n";#移除連線的資訊unset($this->connInfo[$conn->resourceId]);}#function onClose end#當出現錯誤時public function onError(ConnectionInterface $conn, \Exception $e){#印出錯誤訊息echo "An error has occurred: {$e->getMessage()}\n";#關閉與client的socket$conn->close();}#fucntion onError end}#class soldier end#使用 Ratchet\Server\IoServer 類別use Ratchet\Server\IoServer;#使用 Ratchet\WebSocket\WsServer 類別use Ratchet\WebSocket\WsServer;#使用 Ratchet\Http\HttpServer類別use Ratchet\Http\HttpServer;/*類別說明:跟webSocket應用相關的類別.備註:無.*/class webSock{/*#函式說明:#當前類別被呼叫的靜態方法不存在時,將會執行該函數,回報該方法不存在.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$method,物件,為物件實體或類別名稱,會自動置入該參數.#$arguments,陣列,為呼叫方法時所用的參數.#參考資料:#__call=>http://php.net/manual/en/language.oop5.overloading.php#object.callstatic*/public function __call($method,$arguments){#取得當前執行的函式$result["function"]=__FUNCTION__;#設置執行不正常$result["status"]="false";#設置執行錯誤$result["error"][]=__NAMESPACE__ ."/".$method."() 不存在!";#設置所丟入的參數$result["error"][]=$arguments;#回傳結果return $result;}#function __call end/*#函式說明:#當前類別被呼叫的靜態方法不存在時,將會執行該函數,回報該方法不存在.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$method,物件,為物件實體或類別名稱,會自動置入該參數.#$arguments,陣列,為呼叫方法時所用的參數.#參考資料:#__call=>http://php.net/manual/en/language.oop5.overloading.php#object.callstatic*/public static function __callStatic($method,$arguments){#取得當前執行的函式$result["function"]=__FUNCTION__;#設置執行不正常$result["status"]="false";#設置執行錯誤$result["error"][]="欲呼叫的". __NAMESPACE__ ."/".$method."() 不存在!";#設置所丟入的參數$result["error"][]=$arguments;#回傳結果return $result;}#function __callStatic end/*#函式說明:#擴充過的Ratchet的聊天室用戶端與伺服端範例,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["fileArgu"]=__FILE__;#可省略參數:#$conf["disReg"],字串,是否要取消apache的passProxy檢查與設定,預設為"false"不取消,"true"為取消.#$conf["disReg"]="";#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行一次,建立webSocket Server後,再於網頁端執行即可產生webSocket Client端的code.#僅適用於https網頁透過wss連線到web socket server.*/public static function chatRoomDemo(&$conf){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#建立 web socket client 的 js 語法#函式說明:#聊天室用戶端js範例#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["content"],js語法.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world$chatRoomClientDemo=webSock::chatRoomClientDemo();#如果建立聊天室用戶端失敗if($chatRoomClientDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$chatRoomClientDemo;#回傳結果return $result;}#if end#取得聊天室的語法$result["content"]=$chatRoomClientDemo["content"];#設置執行正常$result["status"]="true";#回傳結果return $result;}#if end#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!=="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf===null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容。#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填寫的參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("fileArgu");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可以省略的參數:#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.$conf["variableCheck::checkArguments"]["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array();#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("disReg");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("false");#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料來源:#array_keys=>http://php.net/manual/en/function.array-keys.php#建議:#增加可省略參數全部不能為空字串或空陣列的參數功能.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果參數檢查不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#執行到這邊代表是命令列環境#如果沒有要取消設定 passProxyif($conf["disReg"]==="false"){#確認設定 passProxy#函式說明:#註冊聊天室範例的 passProxy 設定,本函數會用root帳戶去新增.#會在 /etc/httpd/conf/httpd.conf 檔案裡面加上以下內容##Enable the mod_proxy modules in the HTTPD#LoadModule proxy_module modules/mod_proxy.so#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so###ProxyPass##If requeted web address is begin with (ws://hostdns)/wss/chatDemo, then redirect to ws://localhost:8080#ProxyPass /wss/chatDemo ws://localhost:8080#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["webSock::registerChatDemo"]["fileArgu"]=$conf["fileArgu"];#可省略參數:#$conf["rootPasswd"],字串,root帳戶的密碼,預設為"password".#$conf["rootPasswd"]="password";#$conf["httpd.conf"],字串,apache設定檔的路徑與名稱,預設為"/etc/httpd/conf/httpd.conf".#$conf["httpd.conf"]="/etc/httpd/conf/httpd.conf";#備註:#僅能在命令列環境下執行.#改變暫存檔案權限的功能異常.#參考資料:#用apache的passProxy來識別服務並轉到正確的port=>https://groups.google.com/forum/#!topic/ratchet-php/dj-PgPPO_J0$registerChatDemo=webSock::registerChatDemo($conf["webSock::registerChatDemo"]);unset($conf["webSock::registerChatDemo"]);#如果註冊 ChatDemo 服務失敗if($registerChatDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$registerChatDemo;#回傳結果return $result;}#if end}#if end#函式說明:#擴充過的Ratchet聊天室伺服端範例,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行才行.$chatRoomServerDemo=self::chatRoomServerDemo();#如果運行 chatRoomServerDemo 失敗if($chatRoomServerDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$chatRoomServerDemo;#回傳結果return $result;}#if end#設置執行正常$result["status"]="true";#回傳結果return $result;}#function chatRoomDemo end/*#函式說明:#擴充過的Ratchet的聊天室用戶端與伺服端範例第二版,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["fileArgu"]=__FILE__;#可省略參數:#$conf["disReg"],字串,是否要取消apache的passProxy檢查與設定,預設為"false"不取消,"true"為取消.#$conf["disReg"]="";#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行一次,建立webSocket Server後,再於網頁端執行即可產生webSocket Client端的code.#僅適用於https網頁透過wss連線到web socket server.*/public static function chatRoomDemoV2(&$conf){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#建立 web socket client 的 js 語法#函式說明:#聊天室用戶端js範例#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["content"],js語法.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world$chatRoomClientDemo=webSock::chatRoomClientDemoV2();#如果建立聊天室用戶端失敗if($chatRoomClientDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$chatRoomClientDemo;#回傳結果return $result;}#if end#取得聊天室的語法$result["content"]=$chatRoomClientDemo["content"];#設置執行正常$result["status"]="true";#回傳結果return $result;}#if end#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!=="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf===null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容。#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填寫的參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("fileArgu");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可以省略的參數:#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.$conf["variableCheck::checkArguments"]["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array();#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("disReg");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("false");#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料來源:#array_keys=>http://php.net/manual/en/function.array-keys.php#建議:#增加可省略參數全部不能為空字串或空陣列的參數功能.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果參數檢查不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#執行到這邊代表是命令列環境#如果沒有要取消設定 passProxyif($conf["disReg"]==="false"){#確認設定 passProxy#函式說明:#註冊聊天室範例的 passProxy 設定,本函數會用root帳戶去新增.#會在 /etc/httpd/conf/httpd.conf 檔案裡面加上以下內容##Enable the mod_proxy modules in the HTTPD#LoadModule proxy_module modules/mod_proxy.so#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so###ProxyPass##If requeted web address is begin with (ws://hostdns)/wss/chatDemo, then redirect to ws://localhost:8080#ProxyPass /wss/chatDemo ws://localhost:8080#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["webSock::registerChatDemo"]["fileArgu"]=$conf["fileArgu"];#可省略參數:#$conf["rootPasswd"],字串,root帳戶的密碼,預設為"password".#$conf["rootPasswd"]="password";#$conf["httpd.conf"],字串,apache設定檔的路徑與名稱,預設為"/etc/httpd/conf/httpd.conf".#$conf["httpd.conf"]="/etc/httpd/conf/httpd.conf";#備註:#僅能在命令列環境下執行.#改變暫存檔案權限的功能異常.#參考資料:#用apache的passProxy來識別服務並轉到正確的port=>https://groups.google.com/forum/#!topic/ratchet-php/dj-PgPPO_J0$registerChatDemo=webSock::registerChatDemo($conf["webSock::registerChatDemo"]);unset($conf["webSock::registerChatDemo"]);#如果註冊 ChatDemo 服務失敗if($registerChatDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$registerChatDemo;#回傳結果return $result;}#if end}#if end#函式說明:#擴充過的Ratchet聊天室伺服端範例,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行才行.$chatRoomServerDemo=self::chatRoomServerDemoV2();#如果運行 chatRoomServerDemo 失敗if($chatRoomServerDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$chatRoomServerDemo;#回傳結果return $result;}#if end#設置執行正常$result["status"]="true";#回傳結果return $result;}#function chatRoomDemoV2 end/*#函式說明:#擴充過的Ratchet的聊天室用戶端與伺服端範例第二版,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["fileArgu"]=__FILE__;#可省略參數:#$conf["disReg"],字串,是否要取消apache的passProxy檢查與設定,預設為"false"不取消,"true"為取消.#$conf["disReg"]="";#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行一次,建立webSocket Server後,再於網頁端執行即可產生webSocket Client端的code.#僅適用於https網頁透過wss連線到web socket server.*/public static function chatRoomDemoV3(&$conf=array()){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#建立 web socket client 的 js 語法#函式說明:#聊天室用戶端js範例#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["content"],js語法.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world$chatRoomClientDemo=webSock::chatRoomClientDemoV3();#如果建立聊天室用戶端失敗if($chatRoomClientDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$chatRoomClientDemo;#回傳結果return $result;}#if end#取得聊天室的語法$result["content"]=$chatRoomClientDemo["content"];#設置執行正常$result["status"]="true";#回傳結果return $result;}#if end#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!=="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf===null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容。#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填寫的參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("fileArgu");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可以省略的參數:#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.$conf["variableCheck::checkArguments"]["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array();#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("disReg");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("false");#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料來源:#array_keys=>http://php.net/manual/en/function.array-keys.php#建議:#增加可省略參數全部不能為空字串或空陣列的參數功能.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果參數檢查不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#執行到這邊代表是命令列環境#如果沒有要取消設定 passProxyif($conf["disReg"]==="false"){#確認設定 passProxy#函式說明:#註冊聊天室範例的 passProxy 設定,本函數會用root帳戶去新增.#會在 /etc/httpd/conf/httpd.conf 檔案裡面加上以下內容##Enable the mod_proxy modules in the HTTPD#LoadModule proxy_module modules/mod_proxy.so#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so###ProxyPass##If requeted web address is begin with (ws://hostdns)/wss/chatDemo, then redirect to ws://localhost:8080#ProxyPass /wss/chatDemo ws://localhost:8080#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["webSock::registerChatDemo"]["fileArgu"]=$conf["fileArgu"];#可省略參數:#$conf["rootPasswd"],字串,root帳戶的密碼,預設為"password".#$conf["rootPasswd"]="password";#$conf["httpd.conf"],字串,apache設定檔的路徑與名稱,預設為"/etc/httpd/conf/httpd.conf".#$conf["httpd.conf"]="/etc/httpd/conf/httpd.conf";#備註:#僅能在命令列環境下執行.#改變暫存檔案權限的功能異常.#參考資料:#用apache的passProxy來識別服務並轉到正確的port=>https://groups.google.com/forum/#!topic/ratchet-php/dj-PgPPO_J0$registerChatDemo=webSock::registerChatDemo($conf["webSock::registerChatDemo"]);unset($conf["webSock::registerChatDemo"]);#如果註冊 ChatDemo 服務失敗if($registerChatDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$registerChatDemo;#回傳結果return $result;}#if end}#if end#函式說明:#擴充過的Ratchet聊天室伺服端範例,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],__FILE__的內容.$conf["webSock"]["chatRoomServerDemoV3"]["fileArgu"]=$conf["fileArgu"];#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行才行.$chatRoomServerDemo=self::chatRoomServerDemoV3($conf["webSock"]["chatRoomServerDemoV3"]);unset($conf["webSock"]["chatRoomServerDemoV3"]);#如果運行 chatRoomServerDemo 失敗if($chatRoomServerDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$chatRoomServerDemo;#回傳結果return $result;}#if end#設置執行正常$result["status"]="true";#回傳結果return $result;}#function chatRoomDemoV3 end/*#函式說明:#擴充過的Ratchet聊天室伺服端範例,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#無.#可省略參數:#無.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行才行.*/public static function chatRoomServerDemo(){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#如果是在網頁環境#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="函數". __FUNCTION__ ."僅能在命令列環境下執行!";#回傳結果return $result;}#if end#建立 Ratchet 提供的聊天室範例(適用於telnet)#It stores all the established connections, mediates data sent between each client and our Chat application, and catches errors.#we tell the server to enter an event loop, listening for any incoming requests on port 8080.#$server = IoServer::factory(new Chat(),8080);#建立 Ratchet 提供的聊天室範例(適用於用webServer)$server = IoServer::factory(new HttpServer(new WsServer(new Chat())),8080);#執行 server 端程式$server->run();#設置執行正常$result["status"]="true";#回傳結果return $result;}#function chatRoomServerDemo end/*#函式說明:#擴充過的Ratchet聊天室伺服端範例第二版,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#無.#可省略參數:#無.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行才行.*/public static function chatRoomServerDemoV2(){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#如果是在網頁環境#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="函數". __FUNCTION__ ."僅能在命令列環境下執行!";#回傳結果return $result;}#if end#建立 Ratchet 提供的聊天室範例(適用於telnet)#It stores all the established connections, mediates data sent between each client and our Chat application, and catches errors.#we tell the server to enter an event loop, listening for any incoming requests on port 8080.#$server = IoServer::factory(new Chat(),8080);#建立 Ratchet 提供的聊天室範例(適用於用webServer)$server = IoServer::factory(new HttpServer(new WsServer(new ChatV2())),8080);#執行 server 端程式$server->run();#設置執行正常$result["status"]="true";#回傳結果return $result;}#function chatRoomServerDemoV2 end/*#函式說明:#擴充過的Ratchet聊天室伺服端範例第三版,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],__FILE__的內容.$conf["fileArgu"]=__FILE__;#可省略參數:#無.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行才行.*/public static function chatRoomServerDemoV3(&$conf=array()){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="函數 ".$result["function"]." 僅能在命令列環境下運行!";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!=="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf===null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容。#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填寫的參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("fileArgu");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可以省略的參數:#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.$conf["variableCheck::checkArguments"]["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array();#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("entry","connVar","disReg");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string","string","string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("false","conn","false");#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料來源:#array_keys=>http://php.net/manual/en/function.array-keys.php#建議:#增加可省略參數全部不能為空字串或空陣列的參數功能.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果參數檢查不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#物件化ChatV3類別$Chat3=new ChatV3();#設置屬性 fileArgu$Chat3::$fileArgu=$conf["fileArgu"];#建立 Ratchet 提供的聊天室範例(適用於telnet)#It stores all the established connections, mediates data sent between each client and our Chat application, and catches errors.#we tell the server to enter an event loop, listening for any incoming requests on port 8080.#$server = IoServer::factory(new Chat(),8080);#建立 Ratchet 提供的聊天室範例(適用於用webServer)$server = IoServer::factory(new HttpServer(new WsServer($Chat3)),8080);#執行 server 端程式$server->run();#設置執行正常$result["status"]="true";#回傳結果return $result;}#function chatRoomServerDemoV3 end/*#函式說明:#擴充過的Ratchet聊天室伺服端soldier範例.提供cmd:跟sql:指令支援.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],__FILE__的內容.$conf["fileArgu"]=__FILE__;#可省略參數:#$conf["port"],要 listen 的 port#$conf["port"]="8080";#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行才行.*/public static function soldierServerDemo(&$conf){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="函數 ".$result["function"]." 僅能在命令列環境下運行!";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!=="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf===null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容。#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填寫的參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("fileArgu");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可以省略的參數:#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.$conf["variableCheck::checkArguments"]["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array();#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("port");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("integer");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array(8080);#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料來源:#array_keys=>http://php.net/manual/en/function.array-keys.php#建議:#增加可省略參數全部不能為空字串或空陣列的參數功能.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果參數檢查不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#建立 Ratchet 提供的聊天室範例(適用於telnet)#It stores all the established connections, mediates data sent between each client and our Chat application, and catches errors.#we tell the server to enter an event loop, listening for any incoming requests on port 8080.#$server = IoServer::factory(new Chat(),8080);#建立 soldier 物件$soldier=new soldier();#設置fileArgu屬性$soldier::$fileArgu=$conf["fileArgu"];#建立 Ratchet 提供的聊天室範例(適用於用webServer)$server = IoServer::factory(new HttpServer(new WsServer($soldier)),$conf["port"]);#執行 server 端程式$server->run();#設置執行正常$result["status"]="true";#回傳結果return $result;}#function soldierServerDemo end/*#函式說明:#擴充過的Ratchet聊天室用戶端js範例#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["content"],html.#必填參數:#無.#可省略參數:#無.#參考資料:#Ratchet官網=>http://socketo.me/#用apache的proxy來判斷為哪個服務,導到對應的port裡面=>https://groups.google.com/forum/#!topic/ratchet-php/dj-PgPPO_J0#聊天室範例=>http://socketo.me/docs/hello-world#備註:#僅適用於https網頁透過wss連線到web socket server.*/public static function chatRoomClientDemo(){#初始化要回傳的結果$result=array();#初始化儲存html的變數$result["content"]="";#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#初始化帳號密碼$ac="";$pw="";#如果存在 $_SESSION["account"]if(isset($_SESSION["account"])){#取得帳戶$ac=$_SESSION["account"];}#if end#如果 this->$passwordCol 不為 ""if(Chat::$passwordCol!==""){#如果存在 $_SESSION["password"]if(isset($_SESSION["password"])){#取得帳戶$pw=$_SESSION["password"];}#if end}#if end#取得 server 的 ip#涵式說明:#取得伺服器的IP,並回傳。#回傳的結果:#$result,伺服端的IP#備註:#伺服端必須被 localhost 以外的網址連結才會出現正確的IP$getServerIP=csInformation::getServerIP();#設置用戶端連線到webSocket的範例$script="<script>//取得帳號密碼ac='".$ac."';pw='".$pw."';//設置目前尚為連線到 webSocket Serverconnected='false';//設置儲存應該要斷線的webSocket,避免太多連線在伺服器.//wbClosed='';//設置儲存webSocket連線的變數wb='';//連線到 web socketconnWebSock();//連線到 web socketfunction connWebSock(){//建立 web socket 連線到 wss://localhost/wss/chatDemovar conn = new WebSocket('wss://".$getServerIP."/wss/chatDemo');//當連線成功後conn.onopen = function(e){//印出連線成功訊息到consoleconsole.log(\"Connection established!\");//設置已經連上 webSocket serverconnected='true';//另存 webSocket 物件wb=conn;/*//如果存在前一個連線物件if(wbClosed!==''){//提示關閉前個連線console.log(\"close last connection!\");//關閉之前的連線wbClosed.close();//清空wbClosed='';}*/}//當有收到訊息時conn.onmessage = function(e){//將訊息顯現在consoleconsole.log(e.data);//將訊息寫到文字方框裡面$('#history').val(e.data+'\\r\\n'+$('#history').val());//解析json字串data=JSON.parse(e.data);//如果有查到帳號if(ac!==''){//如果要求輸入帳號if(data==='Please input your account! ex:account:ws1'){//傳送帳號conn.send('account:'+ac);}//如果有查到密碼if(pw!==''){//如果要求輸入密碼if(data==='Please input your password! ex:password:ws1'){//傳送密碼conn.send('password:'+pw);}}}}//當連線斷開後conn.onclose = function(e){//印出連線斷開的訊息到console//console.log(\"Connection end!\");//設置未連上 webSocket serverconnected='false';/*//如果有之前的連線物件if(wb!==''){//儲存應該要斷線的webSocket,避免太多連線在伺服器.wbClosed=wb;}*///清空 webSocket 物件wb='';//指定1秒刷新一次setTimeout('connWebSock()',1000);}}//當按下送出按鈕$('#send').on('click',function(){//如果已經連到 webSocket server 了if(connected==='true'){//傳送訊息wb.send($('#input').val());//清空訊息輸入欄$('#input').val('');}});//重新整理頁面function myrefresh(){//重新整理頁面window.location.reload();}</script>";#設置存放歷史訊息的方框#涵式說明:#可以輸入文字的區塊#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必填的參數:$conf["form::inputTextArea"]["name"]="history";#爲文字輸入框的名稱,供接收端辨識用。$conf["form::inputTextArea"]["readOnly"]="true";#爲是否要爲唯讀,如果爲"true",則爲唯讀。反之則爲"false"。#可省略的參數:#$conf["id"],字串,文字區塊的id,供javaScript呼叫用.$conf["form::inputTextArea"]["id"]="history";#$conf["width"]="";#為輸入框的寬度,預設不指定.#$conf["cols"]="";#爲文字輸入框的欄位數(寬),預設爲按照瀏覽器設定值。#$conf["rows"]="";#爲文字輸入框的列數(高),預設爲按照瀏覽器設定值。#$conf["maxInputLength"]="";#爲文字輸入的長度限制,預設無限制。#$conf["defaultText"]="";#爲文字輸入框裏面的預設文字內容,預設是空的。#$conf["class"]=;#爲要套用的css樣式。如果沒有指定 ,則採用預設的css樣式,"__inputTextAreaCssStyle",其屬性爲 "width:100%","height:120px","font-size:30px"#$conf["jsActivitor"]="";#爲觸發js的條件,可以是"onChange"(已改變內容時)...,須搭配$conf["jsSubmitActionTarget"]參數。#$conf["jsAction"]="";#爲該js是要做什麼,可以是"document.testForm.submit()"(傳送名爲testForm的表單內容)...,須搭配$conf["jsActivitor"]參數。#$conf["formStart"]="true";#爲是否要以<form>開頭,"true"表示"是",也可以看成表單的開始,預設為"false".#$conf["formAction"]="";#表單遞交的目的地,若$conf["formStart"]為"true",則該參數不能省略.#$conf["formName"]="";#爲該表單的名稱#$conf["formMethod"]="";#爲傳輸的方法,若沒設定則預設爲post,其他可用的參數爲get。#$conf["formTarget"]="";#為顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。#$conf["formEnd"]="true";#爲是否要以<form>結尾,"true"表示"是",也可以看成表單的結束,預設為"false".#$conf["comment"],字串,輸入方框上面要放哪些註解文字,亦即用label來呈現,同時指定"for"屬性的數值為當前"input"標籤的id,意即參數"name"的內容.#$conf["comment"]="";#$conf["required"],字串,該欄位是否必填,"true"為必填,"false"為可留空,預設為"false".#$conf["required"]="true";#$conf["placeholder"],字串,當沒有內容時要顯示的內容.#$conf["placeholder"]="";#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是",也可以看作新的一列開始,預設為"false".#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是",也可以看成列裏面的元素開始,預設為"false".#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是",也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是",也可以看作該列結束,預設為"false".#參考資料來源:#input=>http://www.w3schools.com/tags/tag_input.asp$inputTextArea=form::inputTextArea($conf["form::inputTextArea"]);unset($conf["form::inputTextArea"]);#如果建立文字方框失敗if($inputTextArea["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$inputTextArea;#回傳結果return $result;}#if end#串連文字訊息方框$result["content"]=$result["content"].$inputTextArea["content"];#設置填寫要傳送的訊息輸入方框#涵式說明:#可以輸入文字的表單#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必填的參數$conf["form::inputText"]["name"]="data";#爲該文字輸入框的名稱,用於讓接收頁面讀取的名稱。$conf["form::inputText"]["readOnly"]="false";#爲該文字框是否可以填寫資料,若要只能觀看不能填寫,那麼就必須將其值設爲"true",反之要設爲"false"#可省略的參數:#$conf["width"]="";#爲文字框的外觀長度,預設為"100%".#$conf["maxInputLength"]="";#爲可輸入的最大位元長度,預設不限制。#$conf["autoFocus"]="true";#是否為將填寫的指標移到該表單,"true"代表要,預設為"false".#$conf["value"]="";#爲該文字框預設要顯示的文字,預設爲""。#$conf["class"]="";#爲要套用的css樣式,若省略,則會套用預設的 "__inputTextCssStyle" 樣式,其屬性爲 "width:100%","font-size:30px"#$conf["jsActivitor"]="";#爲觸發js的條件,可以是"onChange"(已改變內容時)、"onClick"(按下按鈕時)、"onkeyup"(當鍵盤按下放開後)、"onmouseover"(當滑鼠移過去的時候)...,須搭配$conf["jsSubmitActionTarget"]參數。#$conf["jsAction"]="";#爲該js是要做什麼,可以是"document.testForm.submit()"(傳送名爲testForm的表單內容)...,須搭配$conf["jsActivitor"]參數。#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是"。也可以看作新的一列開始,預設為"false".#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是"。也可以看成列裏面的元素開始,預設為"false".#$conf["formStart"]="true";#爲是否要以<form>開頭,"true"表示"是",也可以看成表單的開始,預設為"false".#$conf["formAction"]="";#表單遞交的目的地,若$conf["formStart"]為"true",則該參數不能省略.#$conf["formName"]="";#爲該表單的名稱#$conf["formMethod"]="";#爲傳輸的方法,若沒設定則預設爲post,其他可用的參數爲get。#$conf["formTarget"]="";#為顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。#$conf["tableStart"]="true";#爲該表單是否要以<table>開始。"true"爲是,預設為"false".#$conf["tableClass"]="";#表格要套用的css樣式,若爲"__withoutBorder"的話則套用無框線的預設樣式;若爲"__withBorder"的話,則爲有框線的預設樣式,預設為"__withoutBorder".#$conf["formEnd"]="true";#爲是否要以<form>結尾,"true"表示"是",也可以看成表單的結束,預設為"false".#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是"。也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是"。也可以看作該列結束,預設為"false".#$conf["tableEnd"]="true";#爲該表單是否要以</table>結尾,"true"爲是,預設為"false".#$conf["autocomplete"],字串,是否依據使用者過往輸入的記錄來提示可能要的輸入內容,"on"為啟用,"off"為停用,預設為"on".#$conf["autocomplete"]="off";#$conf["required"],字串,該欄位是否必填,"true"為必填,"false"為可留空,預設為"false".#$conf["required"]="true";#$conf["comment"],字串,輸入方框上面要放哪些註解文字,亦即用label來呈現,同時指定"for"屬性的數值為當前"input"標籤的id,意即參數"name"的內容.#$conf["comment"]="";#$conf["placeholder"],字串,當沒有內容時要顯示的內容.#$conf["placeholder"]="";#$conf["br"],字串,"true"代表最後要換行,預設為"false".#$conf["br"]="true";#$conf["p"],字串,"true"代表最後要空一行,預設為"false".#$conf["p"]="true";#$conf["id"],字串,該元素的id,預設不使用.$conf["form::inputText"]["id"]="input";#參考資料來源:#input=>http://www.w3schools.com/tags/tag_input.asp$inputText=form::inputText($conf["form::inputText"]);unset($conf["form::inputText"]);#如果輸入文字框失敗if($inputText["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$inputText;#回傳結果return $result;}#if end#文字輸入框$result["content"]=$result["content"].$inputText["content"];#設置觸發的按鈕#函式說明:#放置按鈕#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必要的參數:$conf["form::button"]["buttonDisplayValue"]="Send";#爲按鈕上顯示的文字。#可省略的參數:#$conf["buttonStyleName"]="";#可省略,爲按鈕所要使用的css樣式類別名稱,預設的css樣式爲 __simpleButtonLinkDefaultButtonCssStyle 。#其屬性爲 "width","height","font-size","text-align"#其屬性值爲 "100%" , "50" , "30" , "center"#$conf["form::button"]["buttonActionScriptFunction"]="conn.send('Hello!');";#可省略,爲按下按鈕時所要執行的javaScript函式或程式,預設不設定。#"document.forms.formName.submit()"爲傳送名爲testForm的表單內容#"window.print()"爲使用瀏覽器內建工具列印當前網頁#若搭配 javaScript 類別的 confirmWindow 函數的回傳結果,則會有確認視窗的效果.#$conf["buttonBorder"]="";#可省略,爲IE9內會自動產生外框,此爲外框的厚度,屬性值爲正整數,預設爲0。#$conf["disabled"]="true";#可省略,為按鈕的功能是否要取消,若為"true"則代表要取消,若為"false"則代表功能正常,預設為"false".#$conf["tableStart"]="true";#爲是否要表格開始。"false"代表否,"true"代表是。預設爲"false"。#$conf["tableClass"]="";#表格要套用的css樣式,若省略的話,則預設爲 __defaultTbaleCsssStyle 其屬性爲 table-layout:fixed word-break:break-all width:100% ,須搭配 $conf["tablStart"] 與 $conf["tableEnd"] 使用。#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是"。也可以看作新的一列開始,預設為"false".#$conf["trClass"]="__withoutBorder";#<tr>要套用的css樣式,預設為"__withoutBorder",亦即沒有框線的樣式;"__withBorder"則爲有框線的樣式#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是"。也可以看成列裏面的元素開始,預設為"false".#$conf["tdClass"]="__withoutBorder";#<td>要套用的css樣式,"__withoutBorder"爲沒有框線的樣式;__withBorder爲有框線的樣式#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是"。也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是"。也可以看作該列結束,預設為"false".#$conf["tableEnd"]="true";#爲是否要表格結束。"false"代表否,"true"代表是,預設爲"false"。#$conf["formStart"]="true";#爲是否要表單開始,如果爲"true"則代表要表單開始,預設為"false".#$conf["action"]="";#爲表單要傳送到哪個頁面,須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["target"]="";#為目標表單顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["formEnd"]="true";#爲是否要表單結束,如果爲"true"則代表要表單結束,預設為"false".#$conf["formId"],字串,表單的id.#$conf["formId"]="";#$conf["buttonId"],字串,按鈕的id.$conf["form::button"]["buttonId"]="send";#參考資料來源:#http://stackoverflow.com/questions/3014649/how-to-disable-html-button-using-javascript$button=form::button($conf["form::button"]);unset($conf["form::button"]);#如果建立按鈕失敗if($button["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$button;#回傳結果return $result;}#if end#建立跳到別的頁面的連結#涵式說明:#放置超鏈結#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息#$result["content"],語法#$result["function"],當前執行的函數名稱#必填的參數:#$conf["position"],字串,爲要連結到的位置,若留空,將回自動變成"#",則可以搭配ajax傳值.$conf["link::show_link"]["position"]="webSocketT/hangFewSecs.php";#$conf["linkName",字串,爲連結的顯示名稱$conf["link::show_link"]["linkName"]="到別的頁面轉轉";#可省略的參數:#$conf["method"],字串,爲點選連結後,新畫面要如何呈現,可省略預設爲"_self",可用的選項有 _top(覆蓋目前的視窗來顯現新內容) _parent _self _blank(跳新視窗)#$conf["method"]="";#$conf["class"],字串,爲要套用的css超連節樣式,可省略.#$conf["class"]="";#$conf["id"],字串,超連結的id.#$conf["id"]="";#$conf["no_outline"],字串,是否要取消連結的框線,"false為不取消,"true"代表要取消,預設為"false".#$conf["no_outline"]="";$show_link=link::show_link($conf["link::show_link"]);unset($conf["link::show_link"]);#串接超連結$result["content"]=$result["content"].$show_link["content"];#設置用戶端的html與js語法$result["content"]=$result["content"].$button["content"].$script;#設置執行正常$result["status"]="true";#回傳結果return $result;}#function chatRoomClientDemo end/*#函式說明:#擴充過的Ratchet聊天室用戶端js範例第二版#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["content"],html.#必填參數:#無.#可省略參數:#無.#參考資料:#Ratchet官網=>http://socketo.me/#用apache的proxy來判斷為哪個服務,導到對應的port裡面=>https://groups.google.com/forum/#!topic/ratchet-php/dj-PgPPO_J0#聊天室範例=>http://socketo.me/docs/hello-world#備註:#僅適用於https網頁透過wss連線到web socket server.*/public static function chatRoomClientDemoV2(){#初始化要回傳的結果$result=array();#初始化儲存html的變數$result["content"]="";#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#初始化帳號密碼$ac="";$pw="";#如果存在 $_SESSION["account"]if(isset($_SESSION["account"])){#取得帳戶$ac=$_SESSION["account"];}#if end#如果 this->$passwordCol 不為 ""if(Chat::$passwordCol!==""){#如果存在 $_SESSION["password"]if(isset($_SESSION["password"])){#取得帳戶$pw=$_SESSION["password"];}#if end}#if end#取得 server 的 ip#涵式說明:#取得伺服器的IP,並回傳。#回傳的結果:#$result,伺服端的IP#備註:#伺服端必須被 localhost 以外的網址連結才會出現正確的IP$getServerIP=csInformation::getServerIP();#設置用戶端連線到webSocket的範例$script="<script>//取得帳號密碼ac='".$ac."';pw='".$pw."';//設置目前尚為連線到 webSocket Serverconnected='false';//設置儲存應該要斷線的webSocket,避免太多連線在伺服器.wbClosed='';//設置儲存webSocket連線的變數wb='';//設置儲存msgId的變數msgId='';//連線到 web socketconnWebSock();//連線到 web socketfunction connWebSock(){//建立 web socket 連線到 wss://localhost/wss/chatDemovar conn = new WebSocket('wss://".$getServerIP."/wss/chatDemo');//當連線成功後conn.onopen = function(e){//印出連線成功訊息到consoleconsole.log(\"Connection established!\");//設置已經連上 webSocket serverconnected='true';//另存 webSocket 物件wb=conn;//如果存在前一個連線物件if(wbClosed!==''){//提示關閉前個連線console.log(\"close last connection!\");//關閉之前的連線wbClosed.close();//清空wbClosed='';}}//當有收到訊息時conn.onmessage = function(e){//將訊息顯現在consoleconsole.log(e.data);//將訊息寫到文字方框裡面$('#history').val(e.data+'\\r\\n'+$('#history').val());//解析json字串data=JSON.parse(e.data);//如果要要求login的訊息if(data.type==='login'){//如果有查到帳號if(ac!==''){//如果要求輸入帳號if(data.data==='Please input your account! ex:account:ws1'){//傳送帳號conn.send('account:'+ac);}//如果有查到密碼if(pw!==''){//如果要求輸入密碼if(data.data==='Please input your password! ex:password:ws1'){//傳送密碼conn.send('password:'+pw);}}//如果存在既有的msgId,且剛登入成功if(msgId!=='' && data.data==='Login successfully!'){//設置既有的msgIdconn.send('msgId:'+msgId);}//反之如果登入成功else if(data.data==='Login successfully!'){//查詢自己的msgIdconn.send('msgId?');}}}//如果收到的是 'msgId?'else if(data.type==='msgId?'){//設置自己的msgIdmsgId=data.data;}//如果收到的是 'msg' 類型else if(data.type==='msg'){//回傳有收到訊息的確認conn.send('mIndex:'+data.index);}//如果收到的是 'status' 類型else if(data.type==='status'){//如果內容為設置msgId失敗if(data.data==='set msgId failed'){//查詢自己的msgIdconn.send('msgId?');}}}//當連線斷開後conn.onclose = function(e){//設置未連上 webSocket serverconnected='false';//如果有之前的連線物件if(wb!==''){//儲存應該要斷線的webSocket,避免太多連線在伺服器.wbClosed=wb;}//清空 webSocket 物件wb='';//指定1秒刷新一次setTimeout('connWebSock()',1000);}}//當按下送出按鈕$('#send').on('click',function(){//如果已經連到 webSocket server 了if(connected==='true'){//傳送訊息wb.send($('#input').val());//清空訊息輸入欄$('#input').val('');}});//重新整理頁面function myrefresh(){//重新整理頁面window.location.reload();}</script>";#設置存放歷史訊息的方框#涵式說明:#可以輸入文字的區塊#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必填的參數:$conf["form::inputTextArea"]["name"]="history";#爲文字輸入框的名稱,供接收端辨識用。$conf["form::inputTextArea"]["readOnly"]="true";#爲是否要爲唯讀,如果爲"true",則爲唯讀。反之則爲"false"。#可省略的參數:#$conf["id"],字串,文字區塊的id,供javaScript呼叫用.$conf["form::inputTextArea"]["id"]="history";#$conf["width"]="";#為輸入框的寬度,預設不指定.#$conf["cols"]="";#爲文字輸入框的欄位數(寬),預設爲按照瀏覽器設定值。#$conf["rows"]="";#爲文字輸入框的列數(高),預設爲按照瀏覽器設定值。#$conf["maxInputLength"]="";#爲文字輸入的長度限制,預設無限制。#$conf["defaultText"]="";#爲文字輸入框裏面的預設文字內容,預設是空的。#$conf["class"]=;#爲要套用的css樣式。如果沒有指定 ,則採用預設的css樣式,"__inputTextAreaCssStyle",其屬性爲 "width:100%","height:120px","font-size:30px"#$conf["jsActivitor"]="";#爲觸發js的條件,可以是"onChange"(已改變內容時)...,須搭配$conf["jsSubmitActionTarget"]參數。#$conf["jsAction"]="";#爲該js是要做什麼,可以是"document.testForm.submit()"(傳送名爲testForm的表單內容)...,須搭配$conf["jsActivitor"]參數。#$conf["formStart"]="true";#爲是否要以<form>開頭,"true"表示"是",也可以看成表單的開始,預設為"false".#$conf["formAction"]="";#表單遞交的目的地,若$conf["formStart"]為"true",則該參數不能省略.#$conf["formName"]="";#爲該表單的名稱#$conf["formMethod"]="";#爲傳輸的方法,若沒設定則預設爲post,其他可用的參數爲get。#$conf["formTarget"]="";#為顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。#$conf["formEnd"]="true";#爲是否要以<form>結尾,"true"表示"是",也可以看成表單的結束,預設為"false".#$conf["comment"],字串,輸入方框上面要放哪些註解文字,亦即用label來呈現,同時指定"for"屬性的數值為當前"input"標籤的id,意即參數"name"的內容.#$conf["comment"]="";#$conf["required"],字串,該欄位是否必填,"true"為必填,"false"為可留空,預設為"false".#$conf["required"]="true";#$conf["placeholder"],字串,當沒有內容時要顯示的內容.#$conf["placeholder"]="";#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是",也可以看作新的一列開始,預設為"false".#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是",也可以看成列裏面的元素開始,預設為"false".#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是",也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是",也可以看作該列結束,預設為"false".#參考資料來源:#input=>http://www.w3schools.com/tags/tag_input.asp$inputTextArea=form::inputTextArea($conf["form::inputTextArea"]);unset($conf["form::inputTextArea"]);#如果建立文字方框失敗if($inputTextArea["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$inputTextArea;#回傳結果return $result;}#if end#串連文字訊息方框$result["content"]=$result["content"].$inputTextArea["content"];#設置填寫要傳送的訊息輸入方框#涵式說明:#可以輸入文字的表單#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必填的參數$conf["form::inputText"]["name"]="data";#爲該文字輸入框的名稱,用於讓接收頁面讀取的名稱。$conf["form::inputText"]["readOnly"]="false";#爲該文字框是否可以填寫資料,若要只能觀看不能填寫,那麼就必須將其值設爲"true",反之要設爲"false"#可省略的參數:#$conf["width"]="";#爲文字框的外觀長度,預設為"100%".#$conf["maxInputLength"]="";#爲可輸入的最大位元長度,預設不限制。#$conf["autoFocus"]="true";#是否為將填寫的指標移到該表單,"true"代表要,預設為"false".#$conf["value"]="";#爲該文字框預設要顯示的文字,預設爲""。#$conf["class"]="";#爲要套用的css樣式,若省略,則會套用預設的 "__inputTextCssStyle" 樣式,其屬性爲 "width:100%","font-size:30px"#$conf["jsActivitor"]="";#爲觸發js的條件,可以是"onChange"(已改變內容時)、"onClick"(按下按鈕時)、"onkeyup"(當鍵盤按下放開後)、"onmouseover"(當滑鼠移過去的時候)...,須搭配$conf["jsSubmitActionTarget"]參數。#$conf["jsAction"]="";#爲該js是要做什麼,可以是"document.testForm.submit()"(傳送名爲testForm的表單內容)...,須搭配$conf["jsActivitor"]參數。#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是"。也可以看作新的一列開始,預設為"false".#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是"。也可以看成列裏面的元素開始,預設為"false".#$conf["formStart"]="true";#爲是否要以<form>開頭,"true"表示"是",也可以看成表單的開始,預設為"false".#$conf["formAction"]="";#表單遞交的目的地,若$conf["formStart"]為"true",則該參數不能省略.#$conf["formName"]="";#爲該表單的名稱#$conf["formMethod"]="";#爲傳輸的方法,若沒設定則預設爲post,其他可用的參數爲get。#$conf["formTarget"]="";#為顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。#$conf["tableStart"]="true";#爲該表單是否要以<table>開始。"true"爲是,預設為"false".#$conf["tableClass"]="";#表格要套用的css樣式,若爲"__withoutBorder"的話則套用無框線的預設樣式;若爲"__withBorder"的話,則爲有框線的預設樣式,預設為"__withoutBorder".#$conf["formEnd"]="true";#爲是否要以<form>結尾,"true"表示"是",也可以看成表單的結束,預設為"false".#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是"。也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是"。也可以看作該列結束,預設為"false".#$conf["tableEnd"]="true";#爲該表單是否要以</table>結尾,"true"爲是,預設為"false".#$conf["autocomplete"],字串,是否依據使用者過往輸入的記錄來提示可能要的輸入內容,"on"為啟用,"off"為停用,預設為"on".#$conf["autocomplete"]="off";#$conf["required"],字串,該欄位是否必填,"true"為必填,"false"為可留空,預設為"false".#$conf["required"]="true";#$conf["comment"],字串,輸入方框上面要放哪些註解文字,亦即用label來呈現,同時指定"for"屬性的數值為當前"input"標籤的id,意即參數"name"的內容.#$conf["comment"]="";#$conf["placeholder"],字串,當沒有內容時要顯示的內容.#$conf["placeholder"]="";#$conf["br"],字串,"true"代表最後要換行,預設為"false".#$conf["br"]="true";#$conf["p"],字串,"true"代表最後要空一行,預設為"false".#$conf["p"]="true";#$conf["id"],字串,該元素的id,預設不使用.$conf["form::inputText"]["id"]="input";#參考資料來源:#input=>http://www.w3schools.com/tags/tag_input.asp$inputText=form::inputText($conf["form::inputText"]);unset($conf["form::inputText"]);#如果輸入文字框失敗if($inputText["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$inputText;#回傳結果return $result;}#if end#文字輸入框$result["content"]=$result["content"].$inputText["content"];#設置觸發的按鈕#函式說明:#放置按鈕#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必要的參數:$conf["form::button"]["buttonDisplayValue"]="Send";#爲按鈕上顯示的文字。#可省略的參數:#$conf["buttonStyleName"]="";#可省略,爲按鈕所要使用的css樣式類別名稱,預設的css樣式爲 __simpleButtonLinkDefaultButtonCssStyle 。#其屬性爲 "width","height","font-size","text-align"#其屬性值爲 "100%" , "50" , "30" , "center"#$conf["form::button"]["buttonActionScriptFunction"]="conn.send('Hello!');";#可省略,爲按下按鈕時所要執行的javaScript函式或程式,預設不設定。#"document.forms.formName.submit()"爲傳送名爲testForm的表單內容#"window.print()"爲使用瀏覽器內建工具列印當前網頁#若搭配 javaScript 類別的 confirmWindow 函數的回傳結果,則會有確認視窗的效果.#$conf["buttonBorder"]="";#可省略,爲IE9內會自動產生外框,此爲外框的厚度,屬性值爲正整數,預設爲0。#$conf["disabled"]="true";#可省略,為按鈕的功能是否要取消,若為"true"則代表要取消,若為"false"則代表功能正常,預設為"false".#$conf["tableStart"]="true";#爲是否要表格開始。"false"代表否,"true"代表是。預設爲"false"。#$conf["tableClass"]="";#表格要套用的css樣式,若省略的話,則預設爲 __defaultTbaleCsssStyle 其屬性爲 table-layout:fixed word-break:break-all width:100% ,須搭配 $conf["tablStart"] 與 $conf["tableEnd"] 使用。#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是"。也可以看作新的一列開始,預設為"false".#$conf["trClass"]="__withoutBorder";#<tr>要套用的css樣式,預設為"__withoutBorder",亦即沒有框線的樣式;"__withBorder"則爲有框線的樣式#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是"。也可以看成列裏面的元素開始,預設為"false".#$conf["tdClass"]="__withoutBorder";#<td>要套用的css樣式,"__withoutBorder"爲沒有框線的樣式;__withBorder爲有框線的樣式#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是"。也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是"。也可以看作該列結束,預設為"false".#$conf["tableEnd"]="true";#爲是否要表格結束。"false"代表否,"true"代表是,預設爲"false"。#$conf["formStart"]="true";#爲是否要表單開始,如果爲"true"則代表要表單開始,預設為"false".#$conf["action"]="";#爲表單要傳送到哪個頁面,須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["target"]="";#為目標表單顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["formEnd"]="true";#爲是否要表單結束,如果爲"true"則代表要表單結束,預設為"false".#$conf["formId"],字串,表單的id.#$conf["formId"]="";#$conf["buttonId"],字串,按鈕的id.$conf["form::button"]["buttonId"]="send";#參考資料來源:#http://stackoverflow.com/questions/3014649/how-to-disable-html-button-using-javascript$button=form::button($conf["form::button"]);unset($conf["form::button"]);#如果建立按鈕失敗if($button["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$button;#回傳結果return $result;}#if end#建立跳到別的頁面的連結#涵式說明:#放置超鏈結#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息#$result["content"],語法#$result["function"],當前執行的函數名稱#必填的參數:#$conf["position"],字串,爲要連結到的位置,若留空,將回自動變成"#",則可以搭配ajax傳值.$conf["link::show_link"]["position"]="webSocketT/hangFewSecs.php";#$conf["linkName",字串,爲連結的顯示名稱$conf["link::show_link"]["linkName"]="到別的頁面轉轉";#可省略的參數:#$conf["method"],字串,爲點選連結後,新畫面要如何呈現,可省略預設爲"_self",可用的選項有 _top(覆蓋目前的視窗來顯現新內容) _parent _self _blank(跳新視窗)#$conf["method"]="";#$conf["class"],字串,爲要套用的css超連節樣式,可省略.#$conf["class"]="";#$conf["id"],字串,超連結的id.#$conf["id"]="";#$conf["no_outline"],字串,是否要取消連結的框線,"false為不取消,"true"代表要取消,預設為"false".#$conf["no_outline"]="";$show_link=link::show_link($conf["link::show_link"]);unset($conf["link::show_link"]);#串接超連結$result["content"]=$result["content"].$show_link["content"];#設置用戶端的html與js語法$result["content"]=$result["content"].$button["content"].$script;#設置執行正常$result["status"]="true";#回傳結果return $result;}#function chatRoomClientDemoV2 end/*#函式說明:#擴充過的Ratchet聊天室用戶端js範例第三版,擁有在伺服器上執行指令的功能.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["content"],html.#必填參數:#無.#可省略參數:#無.#參考資料:#Ratchet官網=>http://socketo.me/#用apache的proxy來判斷為哪個服務,導到對應的port裡面=>https://groups.google.com/forum/#!topic/ratchet-php/dj-PgPPO_J0#聊天室範例=>http://socketo.me/docs/hello-world#備註:#僅適用於https網頁透過wss連線到web socket server.*/public static function chatRoomClientDemoV3(){#初始化要回傳的結果$result=array();#初始化儲存html的變數$result["content"]="";#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#初始化帳號密碼$ac="";$pw="";#如果存在 $_SESSION["account"]if(isset($_SESSION["account"])){#取得帳戶$ac=$_SESSION["account"];}#if end#如果 this->$passwordCol 不為 ""if(Chat::$passwordCol!==""){#如果存在 $_SESSION["password"]if(isset($_SESSION["password"])){#取得帳戶$pw=$_SESSION["password"];}#if end}#if end#取得 server 的 ip#涵式說明:#取得伺服器的IP,並回傳。#回傳的結果:#$result,伺服端的IP#備註:#伺服端必須被 localhost 以外的網址連結才會出現正確的IP$getServerIP=csInformation::getServerIP();#設置用戶端連線到webSocket的範例$script="<script>//ready 後執行$(document).ready(function(){//取得帳號密碼ac='".$ac."';pw='".$pw."';//設置目前尚為連線到 webSocket Serverconnected='false';//設置儲存應該要斷線的webSocket,避免太多連線在伺服器.wbClosed='';//設置儲存webSocket連線的變數wb='';//設置儲存msgId的變數msgId='';//連線到 web socketconnWebSock();});//連線到 web socketfunction connWebSock(){//建立 web socket 連線到 wss://localhost/wss/chatDemovar conn = new WebSocket('wss://".$getServerIP."/wss/chatDemo');//當連線成功後conn.onopen = function(e){//印出連線成功訊息到consoleconsole.log(\"Connection established!\");//設置已經連上 webSocket serverconnected='true';//另存 webSocket 物件wb=conn;//如果存在前一個連線物件if(wbClosed!==''){//提示關閉前個連線console.log(\"close last connection!\");//關閉之前的連線wbClosed.close();//清空wbClosed='';}}//當有收到訊息時conn.onmessage = function(e){//將訊息顯現在consoleconsole.log(e.data);//將訊息寫到文字方框裡面$('#history').val(e.data+'\\r\\n'+$('#history').val());//解析json字串data=JSON.parse(e.data);//如果要要求login的訊息if(data.type==='login'){//如果有查到帳號if(ac!==''){//如果要求輸入帳號if(data.data==='Please input your account! ex:account:ws1'){//傳送帳號conn.send('account:'+ac);}//如果有查到密碼if(pw!==''){//如果要求輸入密碼if(data.data==='Please input your password! ex:password:ws1'){//傳送密碼conn.send('password:'+pw);}}//如果存在既有的msgId,且剛登入成功if(msgId!=='' && data.data==='Login successfully!'){//設置既有的msgIdconn.send('msgId:'+msgId);}//反之如果登入成功else if(data.data==='Login successfully!'){//查詢自己的msgIdconn.send('msgId?');}}}//如果收到的是 'msgId?'else if(data.type==='msgId?'){//設置自己的msgIdmsgId=data.data;}//如果收到的是 'msg' 類型else if(data.type==='msg'){//回傳有收到訊息的確認conn.send('mIndex:'+data.index);}//如果收到的是 'status' 類型else if(data.type==='status'){//如果內容為設置msgId失敗if(data.data==='set msgId failed'){//查詢自己的msgIdconn.send('msgId?');}}//如果收到的是 'cmd' 類型else if(data.type==='cmd'){//將訊息顯現在console//console.log(e.data);}}//當連線斷開後conn.onclose = function(e){//設置未連上 webSocket serverconnected='false';//如果有之前的連線物件if(wb!==''){//儲存應該要斷線的webSocket,避免太多連線在伺服器.wbClosed=wb;}//清空 webSocket 物件wb='';//指定1秒刷新一次setTimeout('connWebSock()',1000);}}//當按下送出按鈕$('#send').on('click',function(){//如果已經連到 webSocket server 了if(connected==='true'){//傳送訊息wb.send($('#input').val());//清空訊息輸入欄$('#input').val('');}});//重新整理頁面function myrefresh(){//重新整理頁面window.location.reload();}</script>";#設置存放歷史訊息的方框#涵式說明:#可以輸入文字的區塊#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必填的參數:$conf["form::inputTextArea"]["name"]="history";#爲文字輸入框的名稱,供接收端辨識用。$conf["form::inputTextArea"]["readOnly"]="true";#爲是否要爲唯讀,如果爲"true",則爲唯讀。反之則爲"false"。#可省略的參數:#$conf["id"],字串,文字區塊的id,供javaScript呼叫用.$conf["form::inputTextArea"]["id"]="history";#$conf["width"]="";#為輸入框的寬度,預設不指定.#$conf["cols"]="";#爲文字輸入框的欄位數(寬),預設爲按照瀏覽器設定值。#$conf["rows"]="";#爲文字輸入框的列數(高),預設爲按照瀏覽器設定值。#$conf["maxInputLength"]="";#爲文字輸入的長度限制,預設無限制。#$conf["defaultText"]="";#爲文字輸入框裏面的預設文字內容,預設是空的。#$conf["class"]=;#爲要套用的css樣式。如果沒有指定 ,則採用預設的css樣式,"__inputTextAreaCssStyle",其屬性爲 "width:100%","height:120px","font-size:30px"#$conf["jsActivitor"]="";#爲觸發js的條件,可以是"onChange"(已改變內容時)...,須搭配$conf["jsSubmitActionTarget"]參數。#$conf["jsAction"]="";#爲該js是要做什麼,可以是"document.testForm.submit()"(傳送名爲testForm的表單內容)...,須搭配$conf["jsActivitor"]參數。#$conf["formStart"]="true";#爲是否要以<form>開頭,"true"表示"是",也可以看成表單的開始,預設為"false".#$conf["formAction"]="";#表單遞交的目的地,若$conf["formStart"]為"true",則該參數不能省略.#$conf["formName"]="";#爲該表單的名稱#$conf["formMethod"]="";#爲傳輸的方法,若沒設定則預設爲post,其他可用的參數爲get。#$conf["formTarget"]="";#為顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。#$conf["formEnd"]="true";#爲是否要以<form>結尾,"true"表示"是",也可以看成表單的結束,預設為"false".#$conf["comment"],字串,輸入方框上面要放哪些註解文字,亦即用label來呈現,同時指定"for"屬性的數值為當前"input"標籤的id,意即參數"name"的內容.#$conf["comment"]="";#$conf["required"],字串,該欄位是否必填,"true"為必填,"false"為可留空,預設為"false".#$conf["required"]="true";#$conf["placeholder"],字串,當沒有內容時要顯示的內容.#$conf["placeholder"]="";#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是",也可以看作新的一列開始,預設為"false".#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是",也可以看成列裏面的元素開始,預設為"false".#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是",也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是",也可以看作該列結束,預設為"false".#參考資料來源:#input=>http://www.w3schools.com/tags/tag_input.asp$inputTextArea=form::inputTextArea($conf["form::inputTextArea"]);unset($conf["form::inputTextArea"]);#如果建立文字方框失敗if($inputTextArea["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$inputTextArea;#回傳結果return $result;}#if end#串連文字訊息方框$result["content"]=$result["content"].$inputTextArea["content"];#設置填寫要傳送的訊息輸入方框#涵式說明:#可以輸入文字的表單#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必填的參數$conf["form::inputText"]["name"]="data";#爲該文字輸入框的名稱,用於讓接收頁面讀取的名稱。$conf["form::inputText"]["readOnly"]="false";#爲該文字框是否可以填寫資料,若要只能觀看不能填寫,那麼就必須將其值設爲"true",反之要設爲"false"#可省略的參數:#$conf["width"]="";#爲文字框的外觀長度,預設為"100%".#$conf["maxInputLength"]="";#爲可輸入的最大位元長度,預設不限制。#$conf["autoFocus"]="true";#是否為將填寫的指標移到該表單,"true"代表要,預設為"false".#$conf["value"]="";#爲該文字框預設要顯示的文字,預設爲""。#$conf["class"]="";#爲要套用的css樣式,若省略,則會套用預設的 "__inputTextCssStyle" 樣式,其屬性爲 "width:100%","font-size:30px"#$conf["jsActivitor"]="";#爲觸發js的條件,可以是"onChange"(已改變內容時)、"onClick"(按下按鈕時)、"onkeyup"(當鍵盤按下放開後)、"onmouseover"(當滑鼠移過去的時候)...,須搭配$conf["jsSubmitActionTarget"]參數。#$conf["jsAction"]="";#爲該js是要做什麼,可以是"document.testForm.submit()"(傳送名爲testForm的表單內容)...,須搭配$conf["jsActivitor"]參數。#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是"。也可以看作新的一列開始,預設為"false".#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是"。也可以看成列裏面的元素開始,預設為"false".#$conf["formStart"]="true";#爲是否要以<form>開頭,"true"表示"是",也可以看成表單的開始,預設為"false".#$conf["formAction"]="";#表單遞交的目的地,若$conf["formStart"]為"true",則該參數不能省略.#$conf["formName"]="";#爲該表單的名稱#$conf["formMethod"]="";#爲傳輸的方法,若沒設定則預設爲post,其他可用的參數爲get。#$conf["formTarget"]="";#為顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。#$conf["tableStart"]="true";#爲該表單是否要以<table>開始。"true"爲是,預設為"false".#$conf["tableClass"]="";#表格要套用的css樣式,若爲"__withoutBorder"的話則套用無框線的預設樣式;若爲"__withBorder"的話,則爲有框線的預設樣式,預設為"__withoutBorder".#$conf["formEnd"]="true";#爲是否要以<form>結尾,"true"表示"是",也可以看成表單的結束,預設為"false".#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是"。也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是"。也可以看作該列結束,預設為"false".#$conf["tableEnd"]="true";#爲該表單是否要以</table>結尾,"true"爲是,預設為"false".#$conf["autocomplete"],字串,是否依據使用者過往輸入的記錄來提示可能要的輸入內容,"on"為啟用,"off"為停用,預設為"on".#$conf["autocomplete"]="off";#$conf["required"],字串,該欄位是否必填,"true"為必填,"false"為可留空,預設為"false".#$conf["required"]="true";#$conf["comment"],字串,輸入方框上面要放哪些註解文字,亦即用label來呈現,同時指定"for"屬性的數值為當前"input"標籤的id,意即參數"name"的內容.#$conf["comment"]="";#$conf["placeholder"],字串,當沒有內容時要顯示的內容.#$conf["placeholder"]="";#$conf["br"],字串,"true"代表最後要換行,預設為"false".#$conf["br"]="true";#$conf["p"],字串,"true"代表最後要空一行,預設為"false".#$conf["p"]="true";#$conf["id"],字串,該元素的id,預設不使用.$conf["form::inputText"]["id"]="input";#參考資料來源:#input=>http://www.w3schools.com/tags/tag_input.asp$inputText=form::inputText($conf["form::inputText"]);unset($conf["form::inputText"]);#如果輸入文字框失敗if($inputText["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$inputText;#回傳結果return $result;}#if end#文字輸入框$result["content"]=$result["content"].$inputText["content"];#設置觸發的按鈕#函式說明:#放置按鈕#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必要的參數:$conf["form::button"]["buttonDisplayValue"]="Send";#爲按鈕上顯示的文字。#可省略的參數:#$conf["buttonStyleName"]="";#可省略,爲按鈕所要使用的css樣式類別名稱,預設的css樣式爲 __simpleButtonLinkDefaultButtonCssStyle 。#其屬性爲 "width","height","font-size","text-align"#其屬性值爲 "100%" , "50" , "30" , "center"#$conf["form::button"]["buttonActionScriptFunction"]="conn.send('Hello!');";#可省略,爲按下按鈕時所要執行的javaScript函式或程式,預設不設定。#"document.forms.formName.submit()"爲傳送名爲testForm的表單內容#"window.print()"爲使用瀏覽器內建工具列印當前網頁#若搭配 javaScript 類別的 confirmWindow 函數的回傳結果,則會有確認視窗的效果.#$conf["buttonBorder"]="";#可省略,爲IE9內會自動產生外框,此爲外框的厚度,屬性值爲正整數,預設爲0。#$conf["disabled"]="true";#可省略,為按鈕的功能是否要取消,若為"true"則代表要取消,若為"false"則代表功能正常,預設為"false".#$conf["tableStart"]="true";#爲是否要表格開始。"false"代表否,"true"代表是。預設爲"false"。#$conf["tableClass"]="";#表格要套用的css樣式,若省略的話,則預設爲 __defaultTbaleCsssStyle 其屬性爲 table-layout:fixed word-break:break-all width:100% ,須搭配 $conf["tablStart"] 與 $conf["tableEnd"] 使用。#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是"。也可以看作新的一列開始,預設為"false".#$conf["trClass"]="__withoutBorder";#<tr>要套用的css樣式,預設為"__withoutBorder",亦即沒有框線的樣式;"__withBorder"則爲有框線的樣式#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是"。也可以看成列裏面的元素開始,預設為"false".#$conf["tdClass"]="__withoutBorder";#<td>要套用的css樣式,"__withoutBorder"爲沒有框線的樣式;__withBorder爲有框線的樣式#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是"。也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是"。也可以看作該列結束,預設為"false".#$conf["tableEnd"]="true";#爲是否要表格結束。"false"代表否,"true"代表是,預設爲"false"。#$conf["formStart"]="true";#爲是否要表單開始,如果爲"true"則代表要表單開始,預設為"false".#$conf["action"]="";#爲表單要傳送到哪個頁面,須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["target"]="";#為目標表單顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["formEnd"]="true";#爲是否要表單結束,如果爲"true"則代表要表單結束,預設為"false".#$conf["formId"],字串,表單的id.#$conf["formId"]="";#$conf["buttonId"],字串,按鈕的id.$conf["form::button"]["buttonId"]="send";#參考資料來源:#http://stackoverflow.com/questions/3014649/how-to-disable-html-button-using-javascript$button=form::button($conf["form::button"]);unset($conf["form::button"]);#如果建立按鈕失敗if($button["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$button;#回傳結果return $result;}#if end#建立跳到別的頁面的連結#涵式說明:#放置超鏈結#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息#$result["content"],語法#$result["function"],當前執行的函數名稱#必填的參數:#$conf["position"],字串,爲要連結到的位置,若留空,將回自動變成"#",則可以搭配ajax傳值.$conf["link::show_link"]["position"]="webSocketT/hangFewSecs.php";#$conf["linkName",字串,爲連結的顯示名稱$conf["link::show_link"]["linkName"]="到別的頁面轉轉";#可省略的參數:#$conf["method"],字串,爲點選連結後,新畫面要如何呈現,可省略預設爲"_self",可用的選項有 _top(覆蓋目前的視窗來顯現新內容) _parent _self _blank(跳新視窗)#$conf["method"]="";#$conf["class"],字串,爲要套用的css超連節樣式,可省略.#$conf["class"]="";#$conf["id"],字串,超連結的id.#$conf["id"]="";#$conf["no_outline"],字串,是否要取消連結的框線,"false為不取消,"true"代表要取消,預設為"false".#$conf["no_outline"]="";$show_link=link::show_link($conf["link::show_link"]);unset($conf["link::show_link"]);#串接超連結$result["content"]=$result["content"].$show_link["content"];#設置用戶端的html與js語法$result["content"]=$result["content"].$button["content"].$script;#設置執行正常$result["status"]="true";#回傳結果return $result;}#function chatRoomClientDemoV3 end/*#函式說明:#擴充過的Ratchet聊天室silder用戶端js範例,可以不跟ajax排隊.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["content"],html.#必填參數:#無.#可省略參數:#無.#參考資料:#Ratchet官網=>http://socketo.me/#用apache的proxy來判斷為哪個服務,導到對應的port裡面=>https://groups.google.com/forum/#!topic/ratchet-php/dj-PgPPO_J0#聊天室範例=>http://socketo.me/docs/hello-world#備註:#僅適用於https網頁透過wss連線到web socket server.*/public static function soldierClientDemo(){#初始化要回傳的結果$result=array();#初始化儲存html的變數$result["content"]="";#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#初始化帳號密碼$ac="";$pw="";#如果存在 $_SESSION["account"]if(isset($_SESSION["account"])){#取得帳戶$ac=$_SESSION["account"];}#if end#如果 this->$passwordCol 不為 ""if(Chat::$passwordCol!==""){#如果存在 $_SESSION["password"]if(isset($_SESSION["password"])){#取得帳戶$pw=$_SESSION["password"];}#if end}#if end#取得 server 的 ip#涵式說明:#取得伺服器的IP,並回傳。#回傳的結果:#$result,伺服端的IP#備註:#伺服端必須被 localhost 以外的網址連結才會出現正確的IP$getServerIP=csInformation::getServerIP();#設置用戶端連線到webSocket的範例$script="<script>//ready 後執行$(document).ready(function(){//取得帳號密碼ac='".$ac."';pw='".$pw."';//設置目前尚為連線到 webSocket Serverconnected='false';//設置儲存應該要斷線的webSocket,避免太多連線在伺服器.wbClosed='';//設置儲存webSocket連線的變數wb='';//告訴server要執行的指令cmd='ls -al';//連線到 web socketconnWebSock();//榜定按鈕事件buttonEvent();});//連線到 web socketfunction connWebSock(){//建立 web socket 連線到 wss://localhost/wss/chatDemovar conn = new WebSocket('wss://".$getServerIP."/wss/chatDemo');//當連線成功後conn.onopen = function(e){//印出連線成功訊息到consoleconsole.log(\"Connection established!\");//設置已經連上 webSocket serverconnected='true';//另存 webSocket 物件wb=conn;//如果存在前一個連線物件if(wbClosed!==''){//提示關閉前個連線console.log(\"close last connection!\");//關閉之前的連線wbClosed.close();//清空wbClosed='';}}//當有收到訊息時conn.onmessage = function(e){//將訊息顯現在consoleconsole.log(e.data);//解析json字串data=JSON.parse(e.data);//如果要要求login的訊息if(data.type==='login'){//如果有查到帳號if(ac!==''){//如果要求輸入帳號if(data.data==='Please input your account! ex:account:ws1'){//傳送帳號conn.send('account:'+ac);}//如果有查到密碼if(pw!==''){//如果要求輸入密碼if(data.data==='Please input your password! ex:password:ws1'){//傳送密碼conn.send('password:'+pw);}}}//反之如果登入成功else if(data.data==='Login successfully!'){//設置已經驗證成功connected='true';}}//如果收到的是 'cmd' 類型else if(data.type==='cmd'){//將訊息顯現在console//console.log(data.data);}}//當連線斷開後conn.onclose = function(e){//設置未連上 webSocket serverconnected='false';//如果有之前的連線物件if(wb!==''){//儲存應該要斷線的webSocket,避免太多連線在伺服器.wbClosed=wb;}//清空 webSocket 物件wb='';//指定1秒刷新一次setTimeout('connWebSock()',1000);}}//榜定下達命令的按鈕事件function buttonEvent(){//當按下送出按鈕$('#send').on('click',function(){//如果已經連到 webSocket server 了if(connected==='true'){//傳送訊息wb.send('cmd:'+cmd);}});//榜定ajax要求$('#run').on('click',function(){$.ajax({url: 'webSocketT/sleep.php',type:'GET',async:true,data:{},success:function(data, status){console.log(data.toSource());}});});}</script>";#串接script語法$result["content"]=$result["content"].$script;#設置觸發ajax的按鈕#函式說明:#放置按鈕#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必要的參數:$conf["form::button"]["buttonDisplayValue"]="ajax";#爲按鈕上顯示的文字。#可省略的參數:#$conf["buttonStyleName"]="";#可省略,爲按鈕所要使用的css樣式類別名稱,預設的css樣式爲 __simpleButtonLinkDefaultButtonCssStyle 。#其屬性爲 "width","height","font-size","text-align"#其屬性值爲 "100%" , "50" , "30" , "center"#$conf["form::button"]["buttonActionScriptFunction"]="conn.send('Hello!');";#可省略,爲按下按鈕時所要執行的javaScript函式或程式,預設不設定。#"document.forms.formName.submit()"爲傳送名爲testForm的表單內容#"window.print()"爲使用瀏覽器內建工具列印當前網頁#若搭配 javaScript 類別的 confirmWindow 函數的回傳結果,則會有確認視窗的效果.#$conf["buttonBorder"]="";#可省略,爲IE9內會自動產生外框,此爲外框的厚度,屬性值爲正整數,預設爲0。#$conf["disabled"]="true";#可省略,為按鈕的功能是否要取消,若為"true"則代表要取消,若為"false"則代表功能正常,預設為"false".#$conf["tableStart"]="true";#爲是否要表格開始。"false"代表否,"true"代表是。預設爲"false"。#$conf["tableClass"]="";#表格要套用的css樣式,若省略的話,則預設爲 __defaultTbaleCsssStyle 其屬性爲 table-layout:fixed word-break:break-all width:100% ,須搭配 $conf["tablStart"] 與 $conf["tableEnd"] 使用。#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是"。也可以看作新的一列開始,預設為"false".#$conf["trClass"]="__withoutBorder";#<tr>要套用的css樣式,預設為"__withoutBorder",亦即沒有框線的樣式;"__withBorder"則爲有框線的樣式#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是"。也可以看成列裏面的元素開始,預設為"false".#$conf["tdClass"]="__withoutBorder";#<td>要套用的css樣式,"__withoutBorder"爲沒有框線的樣式;__withBorder爲有框線的樣式#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是"。也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是"。也可以看作該列結束,預設為"false".#$conf["tableEnd"]="true";#爲是否要表格結束。"false"代表否,"true"代表是,預設爲"false"。#$conf["formStart"]="true";#爲是否要表單開始,如果爲"true"則代表要表單開始,預設為"false".#$conf["action"]="";#爲表單要傳送到哪個頁面,須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["target"]="";#為目標表單顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["formEnd"]="true";#爲是否要表單結束,如果爲"true"則代表要表單結束,預設為"false".#$conf["formId"],字串,表單的id.#$conf["formId"]="";#$conf["buttonId"],字串,按鈕的id.$conf["form::button"]["buttonId"]="run";#參考資料來源:#http://stackoverflow.com/questions/3014649/how-to-disable-html-button-using-javascript$button=form::button($conf["form::button"]);unset($conf["form::button"]);#如果建立按鈕失敗if($button["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$button;#回傳結果return $result;}#if end#串接按鈕語法$result["content"]=$result["content"].$button["content"];#設置觸發命令的按鈕#函式說明:#放置按鈕#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必要的參數:$conf["form::button"]["buttonDisplayValue"]="Send cmd";#爲按鈕上顯示的文字。#可省略的參數:#$conf["buttonStyleName"]="";#可省略,爲按鈕所要使用的css樣式類別名稱,預設的css樣式爲 __simpleButtonLinkDefaultButtonCssStyle 。#其屬性爲 "width","height","font-size","text-align"#其屬性值爲 "100%" , "50" , "30" , "center"#$conf["form::button"]["buttonActionScriptFunction"]="conn.send('Hello!');";#可省略,爲按下按鈕時所要執行的javaScript函式或程式,預設不設定。#"document.forms.formName.submit()"爲傳送名爲testForm的表單內容#"window.print()"爲使用瀏覽器內建工具列印當前網頁#若搭配 javaScript 類別的 confirmWindow 函數的回傳結果,則會有確認視窗的效果.#$conf["buttonBorder"]="";#可省略,爲IE9內會自動產生外框,此爲外框的厚度,屬性值爲正整數,預設爲0。#$conf["disabled"]="true";#可省略,為按鈕的功能是否要取消,若為"true"則代表要取消,若為"false"則代表功能正常,預設為"false".#$conf["tableStart"]="true";#爲是否要表格開始。"false"代表否,"true"代表是。預設爲"false"。#$conf["tableClass"]="";#表格要套用的css樣式,若省略的話,則預設爲 __defaultTbaleCsssStyle 其屬性爲 table-layout:fixed word-break:break-all width:100% ,須搭配 $conf["tablStart"] 與 $conf["tableEnd"] 使用。#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是"。也可以看作新的一列開始,預設為"false".#$conf["trClass"]="__withoutBorder";#<tr>要套用的css樣式,預設為"__withoutBorder",亦即沒有框線的樣式;"__withBorder"則爲有框線的樣式#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是"。也可以看成列裏面的元素開始,預設為"false".#$conf["tdClass"]="__withoutBorder";#<td>要套用的css樣式,"__withoutBorder"爲沒有框線的樣式;__withBorder爲有框線的樣式#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是"。也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是"。也可以看作該列結束,預設為"false".#$conf["tableEnd"]="true";#爲是否要表格結束。"false"代表否,"true"代表是,預設爲"false"。#$conf["formStart"]="true";#爲是否要表單開始,如果爲"true"則代表要表單開始,預設為"false".#$conf["action"]="";#爲表單要傳送到哪個頁面,須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["target"]="";#為目標表單顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["formEnd"]="true";#爲是否要表單結束,如果爲"true"則代表要表單結束,預設為"false".#$conf["formId"],字串,表單的id.#$conf["formId"]="";#$conf["buttonId"],字串,按鈕的id.$conf["form::button"]["buttonId"]="send";#參考資料來源:#http://stackoverflow.com/questions/3014649/how-to-disable-html-button-using-javascript$button=form::button($conf["form::button"]);unset($conf["form::button"]);#如果建立按鈕失敗if($button["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$button;#回傳結果return $result;}#if end#串接按鈕語法$result["content"]=$result["content"].$button["content"];#設置執行正常$result["status"]="true";#回傳結果return $result;}#function soldierClientDemo end/*#函式說明:#擴充過的Ratchet的聊天室soilier用戶端與伺服端範例,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["fileArgu"]=__FILE__;#可省略參數:#$conf["disReg"],字串,是否要取消apache的passProxy檢查與設定,預設為"false"不取消,"true"為取消.#$conf["disReg"]="";#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行一次,建立webSocket Server後,再於網頁端執行即可產生webSocket Client端的code.#僅適用於https網頁透過wss連線到web socket server.*/public static function soldierDemo(&$conf){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#建立 web socket client 的 js 語法#函式說明:#聊天室用戶端js範例#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["content"],js語法.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world$soldierClientDemo=webSock::soldierClientDemo();#如果建立聊天室用戶端失敗if($soldierClientDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$soldierClientDemo;#回傳結果return $result;}#if end#取得聊天室的語法$result["content"]=$soldierClientDemo["content"];#設置執行正常$result["status"]="true";#回傳結果return $result;}#if end#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!=="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf===null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容。#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填寫的參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("fileArgu");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可以省略的參數:#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.$conf["variableCheck::checkArguments"]["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array();#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("disReg");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("false");#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料來源:#array_keys=>http://php.net/manual/en/function.array-keys.php#建議:#增加可省略參數全部不能為空字串或空陣列的參數功能.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果參數檢查不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#執行到這邊代表是命令列環境#如果沒有要取消設定 passProxyif($conf["disReg"]==="false"){#確認設定 passProxy#函式說明:#註冊聊天室範例的 passProxy 設定,本函數會用root帳戶去新增.#會在 /etc/httpd/conf/httpd.conf 檔案裡面加上以下內容##Enable the mod_proxy modules in the HTTPD#LoadModule proxy_module modules/mod_proxy.so#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so###ProxyPass##If requeted web address is begin with (ws://hostdns)/wss/chatDemo, then redirect to ws://localhost:8080#ProxyPass /wss/chatDemo ws://localhost:8080#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["webSock::registerChatDemo"]["fileArgu"]=$conf["fileArgu"];#可省略參數:#$conf["rootPasswd"],字串,root帳戶的密碼,預設為"password".#$conf["rootPasswd"]="password";#$conf["httpd.conf"],字串,apache設定檔的路徑與名稱,預設為"/etc/httpd/conf/httpd.conf".#$conf["httpd.conf"]="/etc/httpd/conf/httpd.conf";#備註:#僅能在命令列環境下執行.#改變暫存檔案權限的功能異常.#參考資料:#用apache的passProxy來識別服務並轉到正確的port=>https://groups.google.com/forum/#!topic/ratchet-php/dj-PgPPO_J0$registerChatDemo=webSock::registerChatDemo($conf["webSock::registerChatDemo"]);unset($conf["webSock::registerChatDemo"]);#如果註冊 ChatDemo 服務失敗if($registerChatDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$registerChatDemo;#回傳結果return $result;}#if end}#if end#函式說明:#擴充過的Ratchet聊天室伺服端範例,port為8080.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#參考資料:#Ratchet官網=>http://socketo.me/#聊天室範例=>http://socketo.me/docs/hello-world#備註:#必須要在命令列環境下執行才行.$conf["webSock"]["soldierServerDemo"]["fileArgu"]=$conf["fileArgu"];$soldierServerDemo=webSock::soldierServerDemo($conf["webSock"]["soldierServerDemo"]);unset($conf["webSock"]["soldierServerDemo"]);#如果運行 chatRoomServerDemo 失敗if($soldierServerDemo["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$soldierServerDemo;#回傳結果return $result;}#if end#設置執行正常$result["status"]="true";#回傳結果return $result;}#function soldierDemo end/*#函式說明:#註冊Ratchet聊天室範例的 passProxy 設定,本函數會用root帳戶去新增.#會在 /etc/httpd/conf/httpd.conf 檔案裡面加上以下內容##Enable the mod_proxy modules in the HTTPD#LoadModule proxy_module modules/mod_proxy.so#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so###ProxyPass##If requeted web address is begin with (ws://hostdns)/wss/chatDemo, then redirect to ws://localhost:8080#ProxyPass /wss/chatDemo ws://localhost:8080#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["fileArgu"]=__FILE__;#可省略參數:#$conf["rootPasswd"],字串,root帳戶的密碼,預設為"password".#$conf["rootPasswd"]="password";#$conf["httpd.conf"],字串,apache設定檔的路徑與名稱,預設為"/etc/httpd/conf/httpd.conf".#$conf["httpd.conf"]="/etc/httpd/conf/httpd.conf";#備註:#僅能在命令列環境下執行.#改變暫存檔案權限的功能異常.#參考資料:#用apache的passProxy來識別服務並轉到正確的port=>https://groups.google.com/forum/#!topic/ratchet-php/dj-PgPPO_J0*/public static function registerChatDemo(&$conf){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()=="web"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="函數 ".$result["function"]." 僅能在命令列環境下運行!";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf==null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容。#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填寫的參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("fileArgu");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可以省略的參數:#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.#$conf["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["skipableVariableCanNotBeEmpty"]=array();#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("httpd.conf","rootPasswd");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string","string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("/etc/httpd/conf/httpd.conf","password");#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料來源:#array_keys=>http://php.net/manual/en/function.array-keys.php#建議:#增加可省略參數全部不能為空字串或空陣列的參數功能.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果參數檢查不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#取得root密碼#函式說明:#藉由使用者的輸入來確認root使用者密碼是否正確.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["content"],root密碼.#必填參數:#$conf["fileArgu"],字串,__FILE__的內容.$conf["cmd::validRootPasswd"]["fileArgu"]=$conf["fileArgu"];#可省略參數:#$conf["password"],字串,用於驗證root使用者的密碼,若未設定則預設為"rootPasswd".$conf["cmd::validRootPasswd"]["password"]=$conf["rootPasswd"];#備註:#建構中$validRootPasswd=cmd::validRootPasswd($conf["cmd::validRootPasswd"]);unset($conf["cmd::validRootPasswd"]);#如果取得root密碼失敗if($validRootPasswd["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$validRootPasswd;#回傳結果return $result;}#if end#取得root密碼$conf["rootPasswd"]=$validRootPasswd["content"];#檢查httpd設定檔案有無設定載入 proxy 模組與設定 ProxyPass#函式說明:#取得檔的內容並以列為單位搜尋多個關鍵字.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息.#$result["function"],當前執行的函數名稱.#$result["content"],取得讀取到的檔案內容.#$result["founded"],每個關鍵字串尋找的結果,"true"代表有找到,"false"代表沒有找到.#$result["foundedLine"],每個找到的關鍵字是在第幾列找到的,key值與$result["founded"]的key值一樣.#必填的參數:#$conf["file"],字串,檔案的位置與名稱.$conf["cmd::checkFileKeyStrLBL"]["file"]=$conf["httpd.conf"];#$conf["keyStr"],陣列字串,要搜尋每列有哪些關鍵字串.$conf["cmd::checkFileKeyStrLBL"]["keyStr"]=array("LoadModule proxy_module modules/mod_proxy.so","LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so","ProxyPass /wss/chatDemo ws://localhost:8080");#可省略參數:#$conf["username"],字串,要以哪個使用者來執行,預設為執行該php程式的使用者.$conf["cmd::checkFileKeyStrLBL"]["username"]="root";#$conf["password"],字串,使用者對應的密碼,預設不使用.$conf["cmd::checkFileKeyStrLBL"]["password"]=$conf["rootPasswd"];#$conf["fileArgu"],字串,__FILE__的內容,預設為當前檔案的位置.$conf["cmd::checkFileKeyStrLBL"]["fileArgu"]=$conf["fileArgu"];#$conf["tempDir"],字串,暫存資料的目錄位置,預設為".cmd/checkFileKeyStrLBL".#$conf["tempDir"]="";$checkFileKeyStrLBL=cmd::checkFileKeyStrLBL($conf["cmd::checkFileKeyStrLBL"]);unset($conf["cmd::checkFileKeyStrLBL"]);#如果檢查設定值失敗if($checkFileKeyStrLBL["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkFileKeyStrLBL;#回傳結果return $result;}#if end#初始化要加入的設定$settingStr=array("LoadModule proxy_module modules/mod_proxy.so","LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so","ProxyPass /wss/chatDemo ws://localhost:8080");#針對每個關鍵字串列foreach($checkFileKeyStrLBL["founded"] as $index=>$status){#如果沒有找到符合的設定if($status==="true"){#移除要增加到設定檔的變數unset($settingStr[$index]);}#if end}#foreach end#如果有要增加的設定if(count($settingStr)>0){#加入設定到 httpd 設定檔裡面#函式說明:#新增文字內容到檔案裡面#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息.#$result["function"],當前執行的函數名稱.#$result["content"],新增好後的檔案內容.#必填的參數:#$conf["file"],字串,檔案的位置與名稱.$conf["cmd::addTextToFile"]["file"]=$conf["httpd.conf"];#$conf["addStr"],陣列字串,要新增的字串內容.$conf["cmd::addTextToFile"]["addStr"]=$settingStr;#可省略參數:#$conf["username"],字串,要以哪個使用者來執行,預設為執行該php程式的使用者.$conf["cmd::addTextToFile"]["username"]="root";#$conf["password"],字串,使用者對應的密碼,預設為"password".$conf["cmd::addTextToFile"]["password"]=$conf["rootPasswd"];#$conf["fileArgu"],字串,__FILE__的內容,預設為當前檔案的位置.$conf["cmd::addTextToFile"]["fileArgu"]=$conf["fileArgu"];$addTextToFile=cmd::addTextToFile($conf["cmd::addTextToFile"]);unset($conf["cmd::addTextToFile"]);#如果新增內容失敗if($addTextToFile["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$addTextToFile;#回傳結果return $result;}#if end#檢查是否增加成功#檢查httpd設定檔案有無設定載入 proxy 模組與設定 ProxyPass#函式說明:#取得檔的內容並以列為單位搜尋多個關鍵字.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息.#$result["function"],當前執行的函數名稱.#$result["content"],取得讀取到的檔案內容.#$result["founded"],每個關鍵字串尋找的結果,"true"代表有找到,"false"代表沒有找到.#$result["foundedLine"],每個找到的關鍵字是在第幾列找到的,key值與$result["founded"]的key值一樣.#必填的參數:#$conf["file"],字串,檔案的位置與名稱.$conf["cmd::checkFileKeyStrLBL"]["file"]=$conf["httpd.conf"];#$conf["keyStr"],陣列字串,要搜尋每列有哪些關鍵字串.$conf["cmd::checkFileKeyStrLBL"]["keyStr"]=$settingStr;#可省略參數:#$conf["username"],字串,要以哪個使用者來執行,預設為執行該php程式的使用者.$conf["cmd::checkFileKeyStrLBL"]["username"]="root";#$conf["password"],字串,使用者對應的密碼,預設不使用.$conf["cmd::checkFileKeyStrLBL"]["password"]=$conf["rootPasswd"];#$conf["fileArgu"],字串,__FILE__的內容,預設為當前檔案的位置.$conf["cmd::checkFileKeyStrLBL"]["fileArgu"]=$conf["fileArgu"];#$conf["tempDir"],字串,暫存資料的目錄位置,預設為".cmd/checkFileKeyStrLBL".#$conf["tempDir"]="";$checkFileKeyStrLBL=cmd::checkFileKeyStrLBL($conf["cmd::checkFileKeyStrLBL"]);unset($conf["cmd::checkFileKeyStrLBL"]);#如果檢查設定值失敗if($checkFileKeyStrLBL["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkFileKeyStrLBL;#回傳結果return $result;}#if end#如果沒有找到該有設定字串if($checkFileKeyStrLBL["founded"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkFileKeyStrLBL;#設置錯誤訊息$result["error"][]="寫入設定值失敗";#回傳結果return $result;}#if end#重新啟動 httpd 伺服器#函式說明:#呼叫shell執行系統命令,並取得回傳的內容.#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["function"],當前執行的函數名稱.#$result["cmd"],執行的指令內容.#$result["output"],爲執行完二元碼後的輸出陣列.#必填的參數#$conf["command"],字串,要執行的指令與.$conf["external::callShell"]["command"]="systemctl";#$conf["fileArgu"],字串,變數__FILE__的內容.$conf["external::callShell"]["fileArgu"]=$conf["fileArgu"];#可省略參數:#$conf["argu"],陣列字串,指令搭配的參數,預設為空陣列.$conf["external::callShell"]["argu"]=array("restart","httpd");#$conf["arguIsAddr"],陣列字串,指令搭配的哪些參數為路徑,為路徑的參數會進行轉換以便符合呼叫當前函數的位置,預設不指定,若有3個參數,其中第3個參數為路徑,則表示為array("false","false","true").#$conf["arguIsAddr"]=array();#$conf["enablePrintDescription"],字串,是否要印出$conf["printDescription"]的內容,"true"代表要,"false"代表不要,預設為"false".#$conf["enablePrintDescription"]="true";#$conf["printDescription"],字串,執行該外部程式前要印出來的的文字,預設為$conf["command"]的內容.#$conf["printDescription"]="";#$conf["escapeshellarg"],字串,是否要啟用過濾參數,用了比較安全,但可能會出錯,"true"為啟用,"false"為不啟用,預設為"false".$conf["external::callShell"]["escapeshellarg"]="true";#$conf["username"],字串,要用什麼使用者來執行,預設為執行php的使用者,該參數不適用於apache環境.$conf["external::callShell"]["username"]="root";#$conf["password"],字串,與$conf["username"]搭配的使用者密碼,預設不使用密碼,該參數不適用於apache環境.$conf["external::callShell"]["password"]=$conf["rootPasswd"];#$conf["useScript"],字串,是否要啟用Linux的script指令來記錄輸出,"true"代表要;"false"代表不要,預設為"false".#$conf["useScript"]="";#$conf["logFilePath"],字串,當 $conf["useScript"] 為 "true" 時,輸出的內容要暫存到哪裡,預設為 ".qbpwcf_tmp/external/callShell/".#$conf["logFilePath"]=".qbpwcf_tmp/external/callShell/";#$conf["inBackGround"],字串,是否要在背景執行,且不會等待程式執行結束再執行下一個指令,"true"代表是,"false"代表不要,預設為"false",如果$conf["command"]有用「;」區隔的多個指令將會出錯.#$conf["inBackGround"]="";#備註:#不是所有指令都能用apache的身份執行,目前已知java,javac指令無法執行,使用root身份可能會被selinux阻擋.#參考資料:#exec=>http://php.net/manual/en/function.exec.php#escapeshellcmd=>http://php.net/manual/en/function.escapeshellcmd.php#escapeshellarg=>http://php.net/manual/en/function.escapeshellarg.php$callShell=external::callShell($conf["external::callShell"]);unset($conf["external::callShell"]);#如果重新啟動apache失敗if($callShell["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$callShell;#回傳結果return $result;}#if end}#if end#設置執行正常$result["status"]="true";#回傳結果return $result;}#function registerChatDemo end/*#函式說明:#建立php原生的socket tcp/ip server,提供webSocket server支援.#回傳結果:#$result["status"],執行正常與否,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$resutl["function"],當前執行的涵式名稱.#$result["argu"],所使用的參數.#必填參數:#$conf["fileArgu"],字串,變數__FILE__的內容.$conf["fileArgu"]=__FILE__;#可省略參數:#$conf["listenIp"],字串,要接聽的主機ip,預設為本機的ip.#$conf["listenIp"]="";#$conf["listenPort"],字串,要接聽的port,預設為已使用port+1.#$conf["listenPort"]="";#$conf["wsMode"],字串,是否要用webSocket模式,預設為"false",不使用,若為"true"則要使用.#$conf["wsMode"]="false";#$conf["processFuncs"],陣列,針對收到的訊息要呼叫的函式,會帶入一個參數陣列,array("data"=>收到的資料,"serverSock"=>serverSock,"clientSock"=>clientSock,"clientInfo"=>用戶端的資訊,"clientIndex"=>用戶端的索引,"allConn"=>所有連線的用戶端的連線資訊),回傳的結果若為陣列$result,其$result["status"]為"true"時,會結束執行(等待下個訊息);為"false"時,會var_dump結果,然後交給下一個函式執行;為"continue"時,代表交給下一個函式執行.#$conf["processFuncs"]=array();#參考資料:#http://php.net/manual/en/sockets.examples.php#http://us3.php.net/manual/en/function.socket-select.php#response should at least end with "\r"=>http://stackoverflow.com/questions/25739768/websocket-communication-between-chromeclient-and-hotspotserver-status-line#response status code should be 101=>http://stackoverflow.com/questions/29829597/i-get-a-status-200-when-connecting-to-the-websocket-but-it-is-an-error#webSocket實做=>http://srchea.com/build-a-real-time-application-using-html5-websockets#webSocketServer實做=>http://www.cuelogic.com/blog/php-and-html5-websocket-server-and-client-communication/#備註:#僅能在命令列執行.#收到用戶的"id?"訊息,會回傳用戶的id.#收到用戶的"ids?"訊息,會回傳非自己的所有用戶id#收到用戶的"talkTo?"訊息,會回傳目前在跟誰談話.#收到用戶的"talkTo:client-id"訊息,會建立與id對應的用戶對話,此後傳遞的訊息均會給對方.#收到用戶的"quit"訊息,會結束與用戶的連線.#收到用戶的"shutdown"訊息,會重新啟動webSocket server.*/public static function nativeSocketTcpIpServer(&$conf){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="函數 ".$result["function"]." 僅能在命令列環境下運行!";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf==null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容。#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填寫的參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("fileArgu");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可以省略的參數:#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.#$conf["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array();#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("listenIp","listenPort","wsMode","processFuncs");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string","string","string","array");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("127.0.0.1",null,"false",null);#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料來源:#array_keys=>http://php.net/manual/en/function.array-keys.php#建議:#增加可省略參數全部不能為空字串或空陣列的參數功能.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果檢查參數不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果 $conf["listenPort"] 不存在if(!isset($conf["listenPort"])){#用nmap掃port#函式說明:#掃port的程式#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息.#$result["function"],當前執行的函數名稱.#$result["argu"],使用的參數.#$result["content"],掃好可能可以使用的port資訊.#必填參數#無:#可省略參數:#$conf["target"],字串,要掃描的主機,預設為"127.0.0.1",$conf["cmd::nmap"]["target"]=$conf["listenIp"];#$conf["-Pn"],字串,是否要啟用避免ping不到就會掃port失敗的功能,預設為"false".#$conf["-Pn"]="false";$nmap=cmd::nmap($conf["cmd::nmap"]);unset($conf["cmd::nmap"]);#如果掃port失敗if($nmap["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$nmap;#回傳結果return $result;}#if end#如果有掃到portif(count($nmap["content"])>0){#找最大的port#涵式說明:#找最大值,結果會回傳最大值.#回傳的結果:#$result["status"],執行是否正常,"true"為正常,"false"為不正常.#$result["error"],錯誤訊息陣列.#$result["function"],當前執行的函數名稱.#$result["key"],最大值原先的key.#$result["value"],最大值的數字.#必填的參數:$conf["math::getMaxValue"]["rawDataArray"]=$nmap["content"];#爲原始數據$getMaxValue=math::getMaxValue($conf["math::getMaxValue"]);unset($conf["math::getMaxValue"]);#如果找最大port失敗if($getMaxValue["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMaxValue;#回傳結果return $result;}#if end#設置 $conf["listenPort"] 為最大 port+1$conf["listenPort"]=$getMaxValue["value"]+1;#如果port小於4000,會無法讓nmap偵測到有使用if($conf["listenPort"]<4000){#設為4000$conf["listenPort"]="4000";}#if end}#if end}#if end#反之else{#用nmap掃port#函式說明:#掃port的程式#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息.#$result["function"],當前執行的函數名稱.#$result["argu"],使用的參數.#$result["content"],掃好可能可以使用的port資訊.#必填參數#無:#可省略參數:#$conf["target"],字串,要掃描的主機,預設為"127.0.0.1",$conf["cmd::nmap"]["target"]=$conf["listenIp"];#$conf["-Pn"],字串,是否要啟用避免ping不到就會掃port失敗的功能,預設為"false".#$conf["-Pn"]="false";#$conf["fileArgu"],字串,變數__FILE__的內容.$conf["cmd::nmap"]["fileArgu"]=$conf["fileArgu"];$nmap=cmd::nmap($conf["cmd::nmap"]);unset($conf["cmd::nmap"]);#如果掃port失敗if($nmap["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$nmap;#回傳結果return $result;}#if end#如果有掃到portif(count($nmap["content"])>0){#如果要用來建立socket的port已被使用if(in_array($conf["listenPort"],$nmap["content"])){#找最大的port#涵式說明:#找最大值,結果會回傳最大值.#回傳的結果:#$result["status"],執行是否正常,"true"為正常,"false"為不正常.#$result["error"],錯誤訊息陣列.#$result["function"],當前執行的函數名稱.#$result["key"],最大值原先的key.#$result["value"],最大值的數字.#必填的參數:$conf["math::getMaxValue"]["rawDataArray"]=$nmap["content"];#爲原始數據$getMaxValue=math::getMaxValue($conf["math::getMaxValue"]);unset($conf["math::getMaxValue"]);#如果找最大port失敗if($getMaxValue["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMaxValue;#回傳結果return $result;}#if end#設置 $conf["listenPort"] 為最大 port+1$conf["listenPort"]=$getMaxValue["value"]+1;#如果port小於4000,會無法讓nmap偵測到有使用if($conf["listenPort"]<4000){#設為4000$conf["listenPort"]="4000";}#if end}#if end}#if end}#else end#回報任何錯誤#error_reporting(E_ALL);/* Allow the script to hang around waiting for connections. */set_time_limit(0);/* Turn on implicit output flushing so we see what we're getting as it comes in. */#ob_implicit_flush();#設定要listen的主機ip$address = $conf["listenIp"];#設定要listen的port$port = $conf["listenPort"];#重複做,讓socket服務不會結束.do{#如果建立 socket 失敗if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false){#印出錯誤訊息echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";}#if end#設置不等待連線與訊息的到來,變成不會卡位socket_set_nonblock($sock);#SOL_SOCKET => socket level#SO_REUSEADDR => Reports whether local addresses can be reused.socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);#如果 Binds a name to a socket 失敗if (@socket_bind($sock, $address, $port) === false){#儲存錯誤訊息$error=socket_strerror(socket_last_error($sock));#印出錯誤訊息echo "socket_bind() failed: reason: " .$error. PHP_EOL;#判斷錯誤訊息的是否有 "Address already in use"#函式說明:#檢查字串裡面有無指定的關鍵字#回傳的結果:#$result["status"],"true"代表執行成功,"false"代表執行失敗。#$result["error"],錯誤訊息#$result["function"],當前執行的函數名稱.#$result["founded"],是否找到關鍵字,"true"代表有找到關鍵字;"false"代表沒有找到關鍵字。#$result["keyWordCount"],找到的關鍵字數量.#必填的參數:$conf["search::findKeyWord"]["keyWord"]="Address already in use";#想要搜尋的關鍵字$conf["search::findKeyWord"]["string"]=$error;#要被搜尋的字串內容#可省略的參數:#$conf["completeEqual"]="true";#是否內容要完全符合,不能多出任何不符合的內容,預設為不需要完全符合。$findKeyWord=search::findKeyWord($conf["search::findKeyWord"]);unset($conf["search::findKeyWord"]);#如果解析錯誤訊息失敗if($findKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果錯誤原因為socket的port已經被使用了.if($findKeyWord["founded"]==="true"){#port加1$port++;#再次建立socket服務continue;}#if end#反之else{#結束程式exit;}#else}#if end#如果 listen socket 經過嘗試5次後仍然失敗if (socket_listen($sock, 5) === false) {#印出錯誤訊息echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . PHP_EOL;}#if end#初始化儲存已經連線到 socket service 的服務$connections=array();#提示 listen 的 ip 與 portecho "Listen to:".$address.":".$port.PHP_EOL;#重複做,等待別人連線.do{#初始化儲存有需要處理的socket連線$read = array();#初始化一開始建立的socket為要處理的項目$read[] = $sock;#有幾個連線就執行幾次foreach($connections as $conForSockSelect){#產生要合併的陣列$arrayToMerage=array($conForSockSelect["connect"]);#合併陣列$read = array_merge($read,$arrayToMerage);}#foreach end#從socket物件陣列($read)裡面取出有需要處理連線的socket物件.#Set up a blocking call to socket_select$write=array();$except=array();$tv_sec = 1;if(socket_select($read, $write, $except, $tv_sec) < 1){#沒有事情發生echo ".";#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]="";#可省略參數:#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".$conf["webSock::encode"]["ping"]="true";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#參考資料:#https://www.rfc-editor.org/rfc/rfc6455#page-28, Web Socket Base Framing Protocol.#備註:#無.$encode=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#debug#var_dump(__LINE__,$encode);#如果執行失敗if($encode["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$encode;#回傳結果return $result;}#if end#針對每個連線的 clientforeach($connections as $client){#如果有 last ping timeif(isset($client["lastPongTime"])){#如果小於5秒沒有收到pongif(time()-$client["lastPongTime"]<5){#看下一個連線continue;}#if end}#if end#取得用戶socket$clientSock=$client["connect"];#傳送ping給client$socket_write=socket_write($clientSock, $encode["content"][0], strlen($encode["content"][0]));#debug#var_dump(__LINE__,"send ping",$socket_write,socket_strerror(socket_last_error($clientSock)));}#foreach end#下一輪continue;}#if end#有事情發生echo "something happen".PHP_EOL;#如果有socket要處理if(in_array($sock,$read)){#如果有接收到 socket 連線if (($msgsock = socket_accept($sock)) !== false) {#初始化不是既有的 sock$existSock=false;#尋找是哪個 socketfor($i=0;$i<count($connections);$i++){#如果是既有的 sockif($connections[$i]["connect"]===$msgsock){#設置是既有的 sock$existSock=true;}#if end}#for end#如果該 socket 是新的if(!$existSock){#重複做do{#亂數產生連線id#涵式說明:#建立以圖片(PNG格式)呈現的驗證碼.#回傳的解果:#$result["status"],執行是否正常,"true"代表執行成功,"false"代表執行失敗.#$result["error"],錯誤訊息.#$result["function"],檔前執行的函數名稱.#$result["randNumberWord"],傳驗證碼的內容.#$result["imgAddress"],圖片的位置與名稱.#必填的參數:#$conf["imgAddressAndName"],字串,爲驗證碼圖片儲存的位置與名稱,副檔名程式會自動產生$conf["authenticate::validationCode"]["imgAddressAndName"]="no used!";#$conf["fileArgu"],字串,php變數__FILE__的內容,亦即該檔案在檔案系統的絕對路徑$conf["authenticate::validationCode"]["fileArgu"]=$conf["fileArgu"];#可省略的參數:#$conf["num"],字串,爲驗證碼的位數,請輸入阿拉伯數字,預設為"8"位數.#$conf["num"]="8";#$conf["disableImg"],字串,是否要取消驗證碼圖片的輸出,"true"為要取消,預設為"false"為不取消$conf["authenticate::validationCode"]["disableImg"]="true";#$conf["imgToData"],字串,預設為"true"代表將圖片轉存成base64圖片,並將原始圖片移除;反之為"false"#$conf["authenticate::validationCode"]["imgToData"]="true";$validationCode=authenticate::validationCode($conf["authenticate::validationCode"]);unset($conf["authenticate::validationCode"]);#如果產生亂數失敗if($validationCode["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$validationCode;#回傳結果return $result;}#if end#如果不存在既有的連線資訊if(count($connections)<1){#跳出迴圈break;}#if end#初始化連線id的陣列$idArray=array();#針對既有的連線foreach($connections as $exist_conn){#儲存連線id$idArray[]=$exist_conn["id"];}#foreach end}#do end#檢查id有無重複while(in_array($validationCode["randNumberWord"],$idArray));#如果不是 ws 模式if($conf["wsMode"]==="false"){#儲存連線到陣列裡面$connections[]=array("connect"=>$msgsock,"buf"=>"","id"=>$validationCode["randNumberWord"],"talkTo"=>array());}#if end#如果是 ws 模式if($conf["wsMode"]==="true"){#儲存連線到陣列裡面$connections[]=array("connect"=>$msgsock,"buf"=>"","id"=>$validationCode["randNumberWord"],"talkTo"=>array(),"handshaked"=>"false","unmask"=>"false","userAgent"=>"false","3rn"=>0,"receivedMsgFromServer"=>array());}#if end#debug,提示 Server 給予的新 Idecho "new connection:".PHP_EOL;#初始化連線後要回傳的訊息$msg="";#如果不是 ws 模式if($conf["wsMode"]!=="true"){#提示client連上線後得到的訊息$msg = $msg.PHP_EOL."Welcome to the PHP Test Server.".PHP_EOL;$msg = $msg."To quit, type 'quit'. To shut down the server type 'shutdown'.".PHP_EOL;socket_write($msgsock, $msg, strlen($msg));}#if end}#if end}#if end}#if end#重新排序 $connections#函式說明:#將陣列的key重新排序,然後回傳,以便後續存取,也可以指定key的內容,但一定要跟元素數量相同。#回傳的解果:#$result["status"],執行是否成功,"true"代表成功,"false"代表失敗.#$result["error"],執行錯誤的訊息.#$result["function"],當前執行的函數名稱.#$result["dataContent"],儲存陣列元素的內容.#若指定了key的名稱,則 $result["dataContent"] 會變成 $result["dataContent"]["指定的key名稱"]#$result["dataCount"],儲存陣列元素的數量。#必填的參數:$conf["arrays::createV2"]["arrayContent"]=$connections;#陣列變數#可省略的參數:#$conf["specifiesKeyArray"]=array();#指定key的名稱,須與$conf["arrayContent"]的元素數量相同$createV2=arrays::createV2($conf["arrays::createV2"]);unset($conf["arrays::createV2"]);#如果重新排序失敗if($createV2["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$createV2;#回傳結果return $result;}#if end#取得重新排序好的陣列$connections=$createV2["dataContent"];#依據每個 client 的連線foreach($connections as $conIndex => $con){#如果有要處理的socket連線項目if(in_array($con["connect"], $read)){#如果不存在 handshakedif(!isset($con["handshaked"])){#預設為 "false"$con["handshaked"]="false";}#if end#如果有 handshakedif($con["handshaked"]==="true"){#讀取內容$buf = @socket_read($con["connect"], 2048, PHP_BINARY_READ);#設置要 unmask$connections[$conIndex]["unmask"]="true";}#if end#反之else{#讀取內容$buf = @socket_read($con["connect"], 2048, PHP_NORMAL_READ);}#else end#如果讀取出錯if($buf===false){#印出錯誤訊息echo "socket_recv() failed: reason: " . socket_strerror(socket_last_error($con["connect"])) . PHP_EOL;#移除該連線的資料unset($connections[$conIndex]);#跳到下一輪continue;}#if end#如果收到的資料長度為 0 bytesif($buf===""){#關閉 socket msgsocket_close($con["connect"]);#移除該連線的資料unset($connections[$conIndex]);#跳到下一輪continue;}#if end#印出接受的非換行符號內容if($buf!==PHP_EOL){#debugecho "received:".$buf.PHP_EOL;}#if end#如果無 handshakedif($con["handshaked"]!=="true"){#清除換行字元$buf=trim($buf);}#if end#web socket modeif($conf["wsMode"]==="true"){#如果不需要 unmaskif($connections[$conIndex]["unmask"]==="false"){#提示還不用 unmaskecho "don't need unmask now".PHP_EOL;#重新計數 \r\n$connections[$conIndex]["3rn"]=0;}#if end}#if end#如果有內容(不是換行符號)$st=trim($buf);#如果是 ws 模式if($conf["wsMode"]==="true"){#如果尚未 handshakeif($connections[$conIndex]["handshaked"]==="false"){#提示 server 在檢查 handshake 用的 key 是否存在.echo "check Sec-WebSocket-Key ..".PHP_EOL;#handshake#如果收到的內容$buf含有 Sec-WebSocket-Key: 字串開頭,擷取後面的內容存到$matchs裡面.if(preg_match("/Sec-WebSocket-Key: (.*)/",$buf,$matchs)){#提示serve在handshakeecho "do handshake...".PHP_EOL.PHP_EOL;#handshake$key = $matchs[1].'258EAFA5-E914-47DA-95CA-C5AB0DC85B11';$key = base64_encode(sha1($key, true));#設置 handshake 的 header$headers ="HTTP/1.1 101 Switching Protocols".PHP_EOL."Upgrade: websocket".PHP_EOL."Connection: Upgrade".PHP_EOL."Sec-WebSocket-Accept: ".$key.PHP_EOL."X-Powered-By: qbpwcf".PHP_EOL.PHP_EOL;#傳送header給clientsocket_write($con["connect"], $headers);#儲存server傳送給client的訊息#$connections[$conIndex]["receivedMsgFromServer"][]=$headers;#提示serve handshake 完畢echo "handshak done...".PHP_EOL;#設置已經 handshake$connections[$conIndex]["handshaked"]="true";}#if end}#if end}#if end#如果是 ws 模式if($conf["wsMode"]==="true"){#如果尚未 handshake 過if($connections[$conIndex]["handshaked"]==="false"){#跳過continue;}#if end#如果還不用要 unmaskif($connections[$conIndex]["unmask"]==="false"){#跳過continue;}#if end}#if end#如果是 ws 模式if($conf["wsMode"]==="true"){#debug#var_dump(__LINE__,$connections[$conIndex]);#如果已經 handshake 過if($connections[$conIndex]["handshaked"]==="true"){#如果要 unmaskif($connections[$conIndex]["unmask"]==="true"){#如果收到的訊息不為空if(!empty($buf)){echo "start unmask...".PHP_EOL;#debug#var_dump(__LINE__,$buf);#解密 $buf#回傳結果:#$result["function"],當前函式的名稱.#$result["status"],執行結果狀態,"true"代表正常;"false"代表不正常.#$result["content"],unmask後的內容.#$result["type"],訊息的類型,"unknow":代表未定義;"text":代表為文字訊息;"pong":代表為pong.#$result["error"],錯誤訊息陣列.$conf["self::unmask"]["payload"]=$buf;#$conf["self::unmask"]["debug"]="true";$buf=webSock::unmask($conf["self::unmask"]);unset($conf["self::unmask"]);#如果執行失敗if($buf["status"]==="false"){#印出結果var_dump($buf);#結束執行exit;}#if end#如果是 ping 的回應 pongif($buf["type"]==="pong"){#提示收到 pongecho "got pong".PHP_EOL;#更新的連線的 last pong time$connections[$conIndex]["lastPongTime"]=time();#換處理下一則訊息continue;}#if end#如果不是 web socket frameif($buf["type"]==="invalid"){#提示收到非 web socket frameecho "not web socket frame".PHP_EOL;#debug#var_dump(__LINE__,$buf);#換處理下一則訊息continue;}#if end#取得umask後的內容$buf=$buf["content"];#提示 unmask 結束echo "end unmask()".PHP_EOL;#提示 web socket server 收到訊息的長度(bytes)echo "Server receviced plain content(".strlen($buf)."):".PHP_EOL;#提示 web socket server 收到的訊息內容echo $buf.PHP_EOL;}#if end}#if end}#if end}#if end#如果收到的是 id?if($buf === 'id?'){#設置要回傳的訊息$talkback=$connections[$conIndex]["id"];#debug#var_dump(__LINE__,$talkback);#json encode 要回傳的訊息$talkback=json_encode($talkback);#debug#var_dump(__LINE__,$talkback);#如果是 ws 模式if($conf["wsMode"]==="true"){#如果已經 handshake 過if($connections[$conIndex]["handshaked"]==="true"){#如果要 unmaskif($connections[$conIndex]["unmask"]==="true"){#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=$talkback;#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["payloadIsBin"]="false";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#目前$conf["text"]長度超過125會出錯.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#debug#var_dump(__LINE__,$talkback);}#if end}#if end}#if end#反之不為 web socket 訊息else{#儲存成只有一個訊息$talkback["content"][]=$talkback;}#else#針對每個訊息的分段foreach($talkback["content"] as $msg){#debugvar_dump(__LINE__,$msg);#回傳訊息$socket_write=socket_write($connections[$conIndex]["connect"], $msg, strlen($msg));#debugvar_dump(__LINE__,$socket_write,socket_strerror(socket_last_error($con["connect"])));}#foreach end#跳到下一輪continue;}#if end#如果收到的是 ids?if($buf === 'ids?'){#設置要回傳的訊息$talkback=array();#針對每個連線foreach($connections as $conIndex_ids => $con_ids){#如果不是自己if($con_ids["connect"]!==$connections[$conIndex]["connect"]){#記錄其他人的id$talkback[]=$con_ids["id"];}#if end}#foreach end#json encode要回傳的id陣列$talkback=json_encode($talkback);#如果是 ws 模式if($conf["wsMode"]==="true"){#如果已經 handshake 過if($connections[$conIndex]["handshaked"]==="true"){#如果要 unmaskif($connections[$conIndex]["unmask"]==="true"){#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=$talkback;#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["payloadIsBin"]="false";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#目前$conf["text"]長度超過125會出錯.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#debug#var_dump(__LINE__,$talkback);}#if end}#if end}#if end#反之不為 web socket 訊息else{#儲存成只有一個訊息$talkback["content"][]=$talkback;}#else#針對每個訊息的分段foreach($talkback["content"] as $msg){#回傳訊息$socket_write=socket_write($connections[$conIndex]["connect"], $msg, strlen($msg));#debugvar_dump(__LINE__,$socket_write,socket_strerror(socket_last_error($con["connect"])));}#foreach end#跳到下一輪continue;}#if end#如果收到 "talkTo?"if($buf==="talkTo?"){#初始化要講話的id陣列$talkback=array();#有幾個要講話的人就執行幾次foreach($connections[$conIndex]["talkTo"] as $to){#串街要講話的人$talkback[]=$to;}#foreach end#設置要回傳的訊息$talkback=json_encode($talkback).PHP_EOL;#如果是 ws 模式if($conf["wsMode"]==="true"){#如果已經 handshake 過if($connections[$conIndex]["handshaked"]==="true"){#如果要 unmaskif($connections[$conIndex]["unmask"]==="true"){#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=$talkback;#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["payloadIsBin"]="false";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#目前$conf["text"]長度超過125會出錯.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#debug#var_dump(__LINE__,$talkback);}#if end}#if end}#if end#反之不為 web socket 訊息else{#儲存成只有一個訊息$talkback["content"][]=$talkback;}#else#針對每個訊息的分段foreach($talkback["content"] as $msg){#回傳訊息$socket_write=socket_write($connections[$conIndex]["connect"], $msg, strlen($msg));#debug#var_dump(__LINE__,$socket_write,socket_strerror(socket_last_error($con["connect"])));}#foreach end#跳到下一輪continue;}#if end#如果收到的$buf長度大於 "talkTo:"if(strlen($buf)>strlen("talkTo:")){#如果收到開頭為 "talkTo:"#涵式說明:#取得符合特定字首與字尾的字串#回傳的結果:#$result["status"],若爲"true"則代表執行正常;若爲"false"則代表執行失敗。#$result["function"],當前執行的函數名稱.#$result["error"],錯誤訊息陣列.#$result["founded"],若為"true"則代表有找到符合字首條件的結果;若爲"false"則代表沒有找到。#$result["returnString"],爲符合字首條件的字串內容。#必填參數:#$conf["checkString"],字串,要檢查的字串.$conf["search::getMeetConditionsString"]["checkString"]=$buf;#可省略參數:#$conf["frontWord"],字串,用來檢查字首應該要有什麼字串,預設不指定.$conf["search::getMeetConditionsString"]["frontWord"]="talkTo:";#$conf["tailWord"],字串,用來檢查字尾應該要有什麼字串,預設不指定.#$conf["tailWord"]="";#參考資料:#str_spilt(),可以將字串依照字母分割成一個個陣列字串。$getMeetConditionsString=search::getMeetConditionsString($conf["search::getMeetConditionsString"]);unset($conf["search::getMeetConditionsString"]);#如果選找前置字串 "talkTo:" 失敗if($getMeetConditionsString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$getMeetConditionsString;#回傳結果return $result;}#if end#如果存在 "talkTo:" 前置字串if($getMeetConditionsString["founded"]==="true"){#用 "talkTo:" 分割 $buf#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:$conf["stringProcess::spiltString"]["stringIn"]=$buf;#要處理的字串。$conf["stringProcess::spiltString"]["spiltSymbol"]="talkTo:";#爲以哪個符號作爲分割#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果分割字串失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果剛好分割出一筆資料if($spiltString["dataCounts"]===1){#取得自己的id$myId=$connections[$conIndex]["id"];#取得講話對象的id$toId=$spiltString["dataArray"][0];#設置對象不存在的識別$targetExist=false;#設置通話對象的key$targetKey="";#取得除了自己的id以外的所有連線foreach($connections as $index=>$talkInfo){#除了自己的idif($talkInfo["id"]!==$myId){#如果存在要對話的對象if($talkInfo["id"]===$toId){#設置對象存在的識別$targetExist=true;#通話對象的key$targetKey=$index;}#if end}#if end}#for each end#如果通話對象存在if($targetExist){#保存自己的通話對象$connections[$conIndex]["talkTo"][]=$toId;#設置要給自己看的訊息$talkback="您與 ".$toId." 展開對話";#json encode 要給自己看的訊息$talkback=json_encode($talkback).PHP_EOL;#如果是 ws 模式if($conf["wsMode"]==="true"){#如果已經 handshake 過if($connections[$conIndex]["handshaked"]==="true"){#如果要 unmaskif($connections[$conIndex]["unmask"]==="true"){#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=$talkback;#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["payloadIsBin"]="false";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#目前$conf["text"]長度超過125會出錯.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#debug#var_dump(__LINE__,$talkback);}#if end}#if end}#if end#反之不為 web socket 訊息else{#儲存成只有一個訊息$talkback["content"][]=$talkback;}#else#針對每個訊息的分段foreach($talkback["content"] as $msg){#回傳訊息$socket_write=socket_write($connections[$conIndex]["connect"], $msg, strlen($msg));#debug#var_dump(__LINE__,$socket_write,socket_strerror(socket_last_error($con["connect"])));}#foreach end#讓對方可以跟自己對話$connections[$targetKey]["talkTo"][]=$myId;#設置要給對方看的訊息$talkback=$connections[$conIndex]["id"]." 與您展開對話";#json encode 設置要給對方看的訊息$talkback=json_encode($talkback);#如果是 ws 模式if($conf["wsMode"]==="true"){#如果已經 handshake 過if($connections[$conIndex]["handshaked"]==="true"){#如果要 unmaskif($connections[$conIndex]["unmask"]==="true"){#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=$talkback;#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["payloadIsBin"]="false";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#目前$conf["text"]長度超過125會出錯.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#debug#var_dump(__LINE__,$talkback);}#if end}#if end}#if end#反之不為 web socket 訊息else{#儲存成只有一個訊息$talkback["content"][]=$talkback;}#else#針對每個訊息的分段foreach($talkback["content"] as $msg){#給對方看的訊息$socket_write=socket_write($connections[$targetKey]["connect"], $msg, strlen($msg));#debug#var_dump(__LINE__,$socket_write,socket_strerror(socket_last_error($con["connect"])));}#foreach end#換一個連線continue;}#if end}#if end}#if end}#if end#如果收到的是 quitif ($buf === 'quit' ) {#設置要回傳的訊息$talkback="結束與 server 的連線";#json encode 要回傳的訊息$talkback=json_encode($talkback).PHP_EOL;#如果是 ws 模式if($conf["wsMode"]==="true"){#如果已經 handshake 過if($connections[$conIndex]["handshaked"]==="true"){#如果要 unmaskif($connections[$conIndex]["unmask"]==="true"){#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=$talkback;#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["payloadIsBin"]="false";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#目前$conf["text"]長度超過125會出錯.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#debug#var_dump(__LINE__,$talkback);}#if end}#if end}#if end#反之不為 web socket 訊息else{#儲存成只有一個訊息$talkback["content"][]=$talkback;}#else#針對每個訊息的分段foreach($talkback["content"] as $msg){#回傳訊息$socket_write=socket_write($con["connect"], $msg, strlen($msg));#debug#var_dump(__LINE__,$socket_write,socket_strerror(socket_last_error($con["connect"])));}#foreach end#關閉被 client 的連線socket_close($con["connect"]);#清理連線的陣列unset($connections[$conIndex]);#跳到下一輪continue;}#if end#如果收到的是 shutdownif ($buf === 'shutdown') {#設置要回傳的訊息$talkback="Server 即將關閉";#json encode 要回傳的訊息$talkback=json_encode($talkback);#如果是 ws 模式if($conf["wsMode"]==="true"){#如果已經 handshake 過if($connections[$conIndex]["handshaked"]==="true"){#如果要 unmaskif($connections[$conIndex]["unmask"]==="true"){#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=$talkback;#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["payloadIsBin"]="false";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#無.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#debug#var_dump(__LINE__,$talkback);}#if end}#if end}#if end#反之不為 web socket 訊息else{#儲存成只有一個訊息$talkback["content"][]=$talkback;}#else#針對每個訊息的分段foreach($talkback["content"] as $msg){#回傳訊息$socket_write=socket_write($con["connect"], $msg, strlen($msg));#debug#var_dump(__LINE__,$socket_write,socket_strerror(socket_last_error($con["connect"])));}#foreach end#關閉用戶的連線socket_close($con["connect"]);#跳到最外層,結束webSocket serverbreak 2;}#if end#如果有指定的外掛函式if(isset($conf["processFuncs"])){#針對每個用來處理輸入字串的函式foreach($conf["processFuncs"] as $proFunc){#debug#var_dump(__LINE__,$proFunc);#呼叫函式,參數為輸入的字串data跟client socket, server socket, 每個 socket#https://www.php.net/manual/en/function.call-user-func.php$param=array("data"=>&$buf,"serverSock"=>&$sock,"clientSock"=>&$con["connect"],"clientInfo"=>&$connections[$conIndex],"clientIndex"=>&$conIndex,"allConn"=>&$connections);$params=array();$params[]=&$param;$result=call_user_func_array($proFunc,$params);#debug#var_dump(__LINE__,$result);#如果有回傳結果if($result!==NULL){#如果回傳的形態為陣列if(gettype($result)==="array"){#如果執行出錯if($result["status"]==="false"){#提示錯誤echo "run function ".$proFunc." with params:".print_r($params,true)." failed!".PHP_EOL;#提示會往後面執行echo "go next function.".PHP_EOL;#跳到下一輪#continue;}#if end#如果結果為跳下一輪else if($result["status"]==="continue"){#提示成功echo "run function ".$proFunc." with params:".print_r($params,true)." success.".PHP_EOL;#提示會往後面執行echo "go next function.".PHP_EOL;#跳下一輪#continue;}#if end#如果已經被處理好了且不准移交給後面的處理else if($result["status"]==="true"){#提示成功echo "run function ".$proFunc." with params:".print_r($params,true)." success.".PHP_EOL;#提示在此打住.echo "end process,".PHP_EOL;#後面就不做了break;}#if end}#if end#反之回傳形態錯誤else{#提示錯誤echo "run function ".$proFunc." with params:".print_r($params,true)." success, but format of return is incorrect!".PHP_EOL;#提示會往後面執行echo "go next function.".PHP_EOL;}#else end}#if end#如果沒有回傳結果else{#提示錯誤echo "run function ".$proFunc." with params:".print_r($params,true)." success, but there is no return!".PHP_EOL;#跳下一輪#continue;}#else end}#foreach end}#if end#如果有要接收訊息的idif(count($connections[$conIndex]["talkTo"])>0){#初始化要傳送給哪些id$broadcastId=array();#依據每個連線資訊foreach($connections as $index=>$broadcast){#儲存每個$broadcastId[$index]=$broadcast["id"];}#foreach end#檢查哪些人是要接收到訊息的#涵式說明:#檢查多個數值,是否與陣列裏面的某些元素相同。#回傳的結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數#$result["error"],涵式錯誤訊息,若爲""則表示沒有錯誤#$result["founded"][$i],若爲"false"代表沒有相同的元素;反之"true"代表有相同的元素,$i爲第i+1個$conf["inputElement"]參數判斷後的結果.#$result["key"][$i],為找到$conf["inputElement"]第$i+1個元素的值是在$conf["blackBoxElement"]中的哪個元素.#必填的參數:$conf["search::checkEquality"]["inputElement"]=$connections[$conIndex]["talkTo"];#想要找到的變數/數值.$conf["search::checkEquality"]["blackBoxElement"]=$broadcastId;#要從哪些變數/數值去尋找.$checkEquality=search::checkEquality($conf["search::checkEquality"]);unset($conf["search::checkEquality"]);#如果檢查失敗if($checkEquality["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkEquality;#回傳結果return $result;}#if end#針對每個搜尋的結果foreach($checkEquality["founded"] as $key=>$found){#如果有找到if($found==="true"){#取得要接收訊息的msgSock$receiveMsgSock=$connections[$checkEquality["key"][$key]]["connect"];#設置要傳送的訊息$talkback = $connections[$conIndex]["id"]." said ".$buf;#json encode 要傳送的訊息$talkback=json_encode($talkback).PHP_EOL;#如果是 ws 模式if($conf["wsMode"]==="true"){#如果已經 handshake 過if($connections[$conIndex]["handshaked"]==="true"){#如果要 unmaskif($connections[$conIndex]["unmask"]==="true"){#加密$conf["webSock::encode"]["text"]=$talkback;$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);}#if end}#if end}#if end#反之不為 web socket 訊息else{#儲存成只有一個訊息$talkback["content"][]=$talkback;}#else#針對每個訊息的分段foreach($talkback["content"] as $msg){#回傳訊息$socket_write=socket_write($receiveMsgSock, $msg, strlen($msg));#debug#var_dump(__LINE__,$receiveMsgSock,socket_strerror(socket_last_error($receiveMsgSock)));}#foreach end}#if end}#foreach end}#if end}#if end}#foreach end#do end}while(true);#提示關閉 server socketecho "關閉 server socket".PHP_EOL;#關閉 socketsocket_close($sock);#do end}while(true);#設置執行正常$result["status"]="true";#回傳結果return $result;}#function nativeSocketTcpIpServer end/*#函式說明:#連線到webSocket,會印出建立好的unixDomainSocket位置與名稱.#回傳結果:#$result["status"],執行正常與否,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$resutl["function"],當前執行的涵式名稱.#$result["content"],取得的回應.#$result["argu"],所使用的參數.#$result["Sec-WebSocket-Accept"],所得到的Sec-WebSocket-Accept.#必填參數:#無.#可省略參數:#$conf["targetServr"],字串,要連線的目標,預設為"localhost".#$conf["targetServr"]="";#$conf["targetPort"],字串,要連線的目標port.#$conf["targetPort"]="";#$conf["ssl"],字串,是否要走wss,預設為"false",不走wss;反之為"true".#$conf["ssl"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#https://www.php.net/manual/en/function.stream-socket-client.php#https://www.php.net/manual/en/function.stream-context-create.php#https://www.php.net/manual/en/context.ssl.php#備註:#建構中...*/public static function clientDaemon(&$conf){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="函數 ".$result["function"]." 僅能在命令列環境下運行!";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf==null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["simpleError"],簡單表示的錯誤訊息.#$result["function"],當前執行的函式名稱.#$result["argu"],設置給予的參數.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可省略參數:#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");#$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array();#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null、any代表不指定變數形態.其中 resource也包含"resource (closed)".#$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array();#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.#$conf["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array("targetServr","targetPort","ssl","debug");#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("targetServr","targetPort","ssl","debug");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string","string","string","string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("localhost",null,"false","false");#$conf["disallowAllSkipableVarIsEmpty"],字串,是否允許每個可省略參數都為空字串,預設為"true"允許,反之為"false".#$conf["disallowAllSkipableVarIsEmpty"]="";#$conf["disallowAllSkipableVarIsEmptyArray"],字串,是否允許每個可省略參數都為空陣列,預設為"true"允許,反之為"false".#$conf["disallowAllSkipableVarIsEmptyArray"]="";#$conf["disallowAllSkipableVarNotExist"],字串,是否不允許每個可省略參數都不存在,預設為"false"代表允許,反之為"true".#$conf["disallowAllSkipableVarNotExist"]="";#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料:#array_keys=>http://php.net/manual/en/function.array-keys.php#備註:#無.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果檢查參數不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果targetPort沒有設置if(!isset($conf["targetPort"])){#port預設為80$conf["targetPort"]="80";#如果有啟用 sslif($conf["ssl"]==="true"){#port預設為443$conf["targetPort"]="443";}#if end}#if end#回報任何錯誤#error_reporting(E_ALL);#如果要使用 sslif($conf["ssl"]==="true"){#預設的path$path="/";#分割出server位置與對應GET的path#函式說明:#將固定格式的字串分開,並回傳分開的結果.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["argu"],使用的參數.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填參數:#$conf["stringIn"],字串,要處理的字串.$conf["stringProcess::spiltString"]["stringIn"]=$conf["targetServr"];#$conf["spiltSymbol"],字串,爲以哪個符號作爲分割.$conf["stringProcess::spiltString"]["spiltSymbol"]="/";#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";#參考資料:#無.#備註:#無.$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果檢查執行失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#如果含有 /if($spiltString["found"]==="true"){#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["argu"],使用的參數.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填參數:#$conf["stringIn"],字串,要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$conf["targetServr"];#$conf["keyWord"],字串,特定字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="/";#可省略參數:#$conf["recursive"],字串,預設為"false"代表找到一個關鍵字就會停止;"true"代表會即重複執行,知道沒有關鍵字為止.#$conf["recursive"]="true";#$conf["lastResult"],陣列,本函式前次執行的結果,若沒有找到關鍵字,則會改回傳該內容.#$conf["lastResult"]=$delStrBeforeKeyWord;#參考資料:#無.#備註:#無.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果檢查執行失敗if($delStrBeforeKeyWord["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#如果該存在的 / 不存在if($delStrBeforeKeyWord["founded"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$delStrBeforeKeyWord;#回傳結果return $result;}#if end#設置 path$path="/".$delStrBeforeKeyWord["content"];#如果有切出 pathif($spiltString["dataCounts"]>=2){#另存peer host name$peerHostName=$spiltString["dataArray"][0];#更新 targetServr$conf["targetServr"]=$peerHostName;}#if end}#if end#初始化給 stream_context_create 用的參數$paramsForStream_context_create=array();#設置為http相關的參數#$paramsForStream_context_create["http"]=array();#method為HEAD#$paramsForStream_context_create["http"]["method"]="HEAD ".$path;#HTTP/1.1#$paramsForStream_context_create["http"]["protocol_version"]="1.1";#初始化header#$paramsForStream_context_create["http"]["header"]=array();#設置header Host#$paramsForStream_context_create["http"]["header"][]="Host: ".$conf["targetServr"];#設置header Upgrade#$paramsForStream_context_create["http"]["header"][]="Upgrade: websocket";#設置header Connection#$paramsForStream_context_create["http"]["header"][]="Connection: Upgrade";#設置header Sec-WebSocket-Version#$paramsForStream_context_create["http"]["header"][]="Sec-WebSocket-Version: 13";#設置header Sec-WebSocket-Key#$paramsForStream_context_create["http"]["header"][]="Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==";#body content#$paramsForStream_context_create["http"]["content"]="";#設置為ssl相關的參數$paramsForStream_context_create["ssl"]=array();#被連線端的網域名稱#$paramsForStream_context_create["ssl"]["peer_name"]=$conf["targetServr"];#verify_peer#$paramsForStream_context_create["ssl"]["verify_peer"]=true;#$paramsForStream_context_create["ssl"]["verify_peer"]=false;#verify_peer_name#$paramsForStream_context_create["ssl"]["verify_peer_name"]=true;#$paramsForStream_context_create["ssl"]["verify_peer_name"]=false;#allow_self_signed,允許沒有受到認可的憑證#$paramsForStream_context_create["ssl"]["allow_self_signed"]=false;#cafile$paramsForStream_context_create["ssl"]["cafile"]="/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem";#capath#$paramsForStream_context_create["ssl"]["capath"]="/etc/pki/ca-trust/extracted/pem/directory-hash/";#local_cert#$paramsForStream_context_create["ssl"]["local_cert"]="/etc/pki/tls/certs/php-selfsigned-and-key.crt";#local_pk#$paramsForStream_context_create["ssl"]["local_pk"]="/etc/pki/tls/private/php-selfsigned.key";#capture_peer_cert$paramsForStream_context_create["ssl"]["capture_peer_cert"]=true;#capture_peer_cert_chain$paramsForStream_context_create["ssl"]["capture_peer_cert_chain"]=true;#security_level#$paramsForStream_context_create["ssl"]["security_level"]=5;#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$paramsForStream_context_create);}#if end#建立ssl設定$stream_context_create=stream_context_create($paramsForStream_context_create);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$stream_context_create);}#if end#連線到 $conf["targetServr"].":".$conf["targetPort"] ,若有 error 可從 $error_code,$error_message 取得資訊, timeout 為 30 秒, connection flags 為 STREAM_CLIENT_CONNECT, 連線的屬性記載在 $stream_context_create.$stream_socket_client=stream_socket_client("ssl://".$conf["targetServr"].":".$conf["targetPort"],$error_code,$error_message,0,STREAM_CLIENT_CONNECT,$stream_context_create);#如果連線到 peer 失敗if($stream_socket_client===false){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="stream_socket_client() failed.".PHP_EOL."Reason: ".$error_message."(".$error_code.")".PHP_EOL;#回傳結果return $result;}#if end#取得連線的資訊$result["info"]=stream_get_meta_data($stream_socket_client);#write header - start#initial header$header="";#method、path、protocol$header=$header."HEAD ".$path." HTTP/1.1"."\r\n";#Host$header=$header."Host: ".$conf["targetServr"]."\r\n";#Upgrade$header=$header."Upgrade: websocket"."\r\n";#Connection$header=$header."Connection: Upgrade"."\r\n";#Sec-WebSocket-Version$header=$header."Sec-WebSocket-Version: 13"."\r\n";#Sec-WebSocket-Key$header=$header."Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ=="."\r\n";#send headerfwrite($stream_socket_client,$header."\r\n");#write header - close#GET server reponsewhile(!feof($stream_socket_client)){#讀取內容$fgets=fgets($stream_socket_client, 1024);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$fgets);}#if end#如果 server 已經回應要用 websocket 協定了if(trim($fgets)==="Upgrade: websocket"){#跳出whilebreak;}#if end}#if end#將建立的 sock 放到 $master 陣列$master[] = $stream_socket_client;#函式說明:#取得目前瀏覽的頁面的路徑或執行的php程式路徑.#回傳結果:#$result["status"],執行是否正常,"true"代表執行成功,"false"代表執行失敗.#$result["error"],錯誤訊息.#$result["function"],檔前執行的函數名稱.#$result["content"],目前瀏覽的頁面的路徑或執行的php程式路徑.#$result["serverIp"],取得伺服器ip.#$result["scheme"],取得與伺服器連線所使用的通訊協定.#必填參數:$conf["csInformation::getPathOfThisPhpFile"]["type"]="pathOnly";#想要取得的路徑類型,"full"代表完整路徑,"pathOnly"代表只要路徑,"lastLayer"代表上一層目錄的名稱#必填參數:#無.#可省略參數:#無.#參考資料:#http://blog.longwin.com.tw/2009/01/php-get-directory-file-path-dirname-2008/#備註:#無.$getPathOfThisPhpFile=csInformation::getPathOfThisPhpFile($conf["csInformation::getPathOfThisPhpFile"]);unset($conf["csInformation::getPathOfThisPhpFile"]);#如果執行失敗if($getPathOfThisPhpFile["status"]=="false"){#設置錯誤識別$result["status"]="false";#設置錯誤訊息$result["error"]=$getPathOfThisPhpFile;#回傳結果return $result;}#if end#函式說明:#使用 linux 的 uuid 指令來產生 uuid 字串#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息.#$result["function"],當前執行的函式名稱.#$result["content"],uuid.#必填參數:#無.#可省略參數:#無.#參考資料:#無.#備註:#無.$uuid=cmd::uuid();#如果執行失敗if($uuid["status"]=="false"){#設置錯誤識別$result["status"]="false";#設置錯誤訊息$result["error"]=$uuid;#回傳結果return $result;}#if end#設置存放socket的path$socketPath=$getPathOfThisPhpFile["content"]."var/webSock::clientDaemon";#讓存放unix domain socket的路徑存在#函式說明:#確保路徑存在.#回傳結果:#$result["status"],執行正常與否,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$resutl["function"],當前執行的涵式名稱.#$result["path"],建立好的路徑字串.#$result["fileName"],檔案名稱,若 $conf["haveFileName"] 為 "true" 則會回傳.#$result["argu"],使用的參數.#必填參數:#$conf["path"],要檢查的路徑$conf["fileAccess::validatePath"]["path"]=$socketPath;#$conf["fileArgu"],字串,php變數__FILE__的內容,亦即該檔案在檔案系統的絕對路徑$conf["fileAccess::validatePath"]["fileArgu"]=__FILE__;#可省略參數:#$conf["haveFileName"],字串,"true"代表有$conf["path"]檔案名稱,"false"代表$conf["path"]為純路徑,預設為"false".$conf["fileAccess::validatePath"]["haveFileName"]="false";#$conf["dirPermission"],字串,新建資料夾的權限設定,預設爲0770,亦即擁有者,同群組者可以讀,寫,存取,其他人無法使用.#$conf["dirPermission"]="";#$conf["web"],是否為檔案系統,"true"為網頁路徑,"false"為網頁系統,預設為"false".$conf["fileAccess::validatePath"]["web"]="false";#參考資料:#無.#備註:#無.$validatePath=fileAccess::validatePath($conf["fileAccess::validatePath"]);unset($conf["fileAccess::validatePath"]);#如果執行失敗if($validatePath["status"]==="false"){#設置錯誤識別$result["status"]="false";#設置錯誤訊息$result["error"]=$validatePath;#回傳結果return $result;}#if end#變更 working dir$chdir=chdir($socketPath);#設置sock檔案名稱$socketName=$uuid["content"].".sock";#設置sock檔案位置與名稱$socketAddr=$socketPath."/".$socketName;#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$socketAddr);}#if end#建立 unix domain socket$usock=stream_socket_server("unix://".$socketName, $errno, $errstr);#如果建立 unix domain socket 失敗if(!$usock){#設置執行失敗$result["status"]="false";#設置錯誤訊息$result["error"][]=$errstr." (".$errno.")";#設置錯誤訊息$result["error"][]="建立 unix domain socket(".$socketAddr.") 失敗";#回傳結果return $result;}#if end#印出socket addrecho "unixDomainSocket:".$socketAddr;#將建立的 unix domain socket 放到 $master 陣列$master[] = $usock;#永久監聽, 不 timeoutwhile(true){#設置給 stream_select 監控的 sock 變數$read = $write = $except = $master;#等待1秒,看有沒有連線進來讀寫資料$mod_fd = stream_select($read, $write, $except, 1);#如果沒有偵測到讀寫動作失敗if($mod_fd===FALSE){#關閉 web socket 連線@fclose($stream_socket_client);#關閉unix domain socket@fclose($usock);#移除unix domain socket@unlink($socketAddr);#設置執行失敗$result["status"]="false";#設置錯誤訊息$result["error"][]="監聽資源異動失敗";#回傳結果return $result;}#if end#如果沒有訊息,代表閒置時可以做的事情else if($mod_fd===0){#代表沒收到訊息echo ".";}#if end#反之有收到來自 web socket server 或 unix socket 的訊息else{#針對每個 sock 陣列foreach($read as $readStream){#如果是來自 web socket server 的訊息if($readStream===$stream_socket_client){#當等待別人連線時,若有人連線進來.#$webConn = stream_socket_accept($stream_socket_client);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,"有收到來自 web socket server 的訊息");}#if end#讀取內容$fread=fread($stream_socket_client,1024);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,strlen($fread),$fread);}#if end#函式說明:#將 handshake 後含有 mask bit 的 web socket 訊息進行 mask/unmask.#回傳結果:#$result["function"],當前函式的名稱.#$result["argu"],使用的參數.#$result["status"],執行結果狀態,"true"代表正常;"false"代表不正常.#$result["content"],unmask後的內容.#$result["type"],訊息的類型,"unknow":代表未定義;"text":代表為文字訊息;"pong":代表為pong;"invalid":代表不為web socket frame.#$result["error"],錯誤訊息陣列.#必填參數:#$conf["payload"],字串,要解密的訊息.$conf["webSock::unmask"]["payload"]=$fread;#可省略參數:#$conf["allowUnmask"],字串,若發現沒有設置mask bit,也要繼續執行,則為"true";反之為"false".$conf["webSock::unmask"]["allowUnmask"]="true";#$conf["webSock::unmask"]["debug"]="true";#參考資料#http://www.inanzzz.com/index.php/post/swf8/converting-string-to-binary-and-binary-to-string-with-php#https://tools.ietf.org/html/rfc6455#https://tools.ietf.org/html/rfc5234#備註:#無.$unmask=webSock::unmask($conf["webSock::unmask"]);unset($conf["webSock::unmask"]);#debug#var_dump(__LINE__,$unmask);#如果出錯if($unmask["status"]==="false"){#關閉 web socket 連線@fclose($stream_socket_client);#關閉unix domain socket@fclose($usock);#移除unix domain socket@unlink($socketAddr);#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$unmask;#回傳結果return $result;}#if end#如果收到文字訊息if($unmask["type"]==="text"){#如果有解析出內容if(isset($unmask["content"])){#提示收到的訊息echo $unmask["content"];#傳遞給unix domain client$fwrite=fwrite($unixConn,$unmask["content"]);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$fwrite);}#if end#關閉連線fclose($unixConn);}#if end}#if end#如果收到pingif($unmask["type"]==="ping"){#函式說明:#加密 handshake 後要傳送的 webSocket 訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]="";#可省略參數:#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="true";#$conf["pong"],字串,"true"代表為ping訊息;反之為"false",預設為"false".$conf["webSock::encode"]["pong"]="true";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.$conf["webSock::encode"]["mask"]="true";#參考資料:#https://www.rfc-editor.org/rfc/rfc6455#page-28, Web Socket Base Framing Protocol.#備註:#無.$encode=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$encode);}#if end#如果出錯if($encode["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$encode;#回傳結果return $result;}#if end#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$encode);}#if end#針對每個 frameforeach($encode["content"] as $fNo => $frame){#傳遞給 web socket server$fwrite=fwrite($stream_socket_client,$frame);#如果傳遞失敗if($fwrite===false){#關閉 web socket 連線@fclose($stream_socket_client);#關閉unix domain socket@fclose($usock);#移除unix domain socket@unlink($socketAddr);#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="傳遞第 ".($fNo+1)." 個 frame 時出錯(總共有".count($encode["content"])."個frame)";#回傳結果return $result;}#if end}#foreach end}#if end}#if end#反之若為來自 unix domain socket 的訊息else if($readStream===$usock){#當等待別人連線時,若有人連線進來.$unixConn = stream_socket_accept($usock);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,"有收到來自 unix domain socket 的訊息");}#if end#讀取內容$fgets=trim(fgets($unixConn,1024));#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,strlen($fgets),$fgets);}#if end#轉換成 web socket 的格式#函式說明:#加密 handshake 後要傳送的 webSocket 訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=$fgets;#可省略參數:#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="true";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.$conf["webSock::encode"]["mask"]="true";#參考資料:#https://www.rfc-editor.org/rfc/rfc6455#page-28, Web Socket Base Framing Protocol.#備註:#無.$encode=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$encode);}#if end#如果出錯if($encode["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$encode;#回傳結果return $result;}#if end#針對每個frameforeach($encode["content"] as $fNo => $frame){#傳遞給 web socket server$fwrite=fwrite($stream_socket_client,$frame);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$fwrite,"傳遞".strlen($frame)."bytes給webSocketServer",$frame);}#if end#如果傳遞失敗if($fwrite===false){#關閉 web socket 連線@fclose($stream_socket_client);#關閉unix domain socket@fclose($usock);#移除unix domain socket@unlink($socketAddr);#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="傳遞第 ".($fNo+1)." 個 frame 時出錯(總共有".count($encode["content"])."個frame)";#回傳結果return $result;}#if end}#foreach end}#if end#例外狀況else{#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$readStream);}#if end#關閉 web socket 連線@fclose($stream_socket_client);#關閉unix domain socket@fclose($usock);#移除unix domain socket@unlink($socketAddr);#顯示 socket 的狀態echo "非預期的錯誤,偵測到不應存在資源有異動".PHP_EOL;#結束執行並回傳1,代表異常結束exit(1);}#else end}#foreach end}#else#等待1秒sleep(1);}#while end#設置執行正常$result["status"]="true";#回傳結果return $result;}#if end#反之不用else{#如果要 debugif($conf["debug"]==="true"){#提示用戶端的文字echo "TCP/IP Connection".PHP_EOL;}#if end/* Get the port for the WWW service. */#http://php.net/manual/en/function.getservbyname.php#$service_port = getservbyname('www', 'tcp');/* Get the IP address for the target host. */#http://php.net/manual/en/function.gethostbyname.php$ServerAddress = gethostbyname($conf["targetServr"]);/* Create a TCP/IP socket. */$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);#如果建立 socket 失敗if ($socket === false) {#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";#回傳結果return $result;}#if end#反之else {#如果要 debugif($conf["debug"]==="true"){#印出建立成功訊息echo "OK.".PHP_EOL;}#if end}#else end#如果要 debugif($conf["debug"]==="true"){#提示要連線到哪個位址的哪個portecho "Attempting to connect to ".$ServerAddress." on port ".$conf["targetPort"]."...";}#if end#連線到目標 socket$socket_connect=socket_connect($socket, $ServerAddress, $conf["targetPort"]);#如果連線到 socket 失敗if($socket_connect===false){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="socket_connect() failed.".PHP_EOL."Reason: ($socket_connect) " . socket_strerror(socket_last_error($socket)) . PHP_EOL;#回傳結果return $result;}#if end#反之else {#如果要 debugif($conf["debug"]==="true"){#印出連線成功訊息echo "OK.".PHP_EOL;}#if end}#else end}#else end#初始化要傳送的HEAD資訊$in="HEAD / HTTP/1.1"."\r\n";$in=$in."Host: ".$ServerAddress.":".$conf["targetPort"]."\r\n";$in=$in."Upgrade: websocket"."\r\n";$in=$in."Connection: Upgrade"."\r\n";$in=$in."Sec-WebSocket-Version: 13"."\r\n";$in=$in."Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ=="."\r\n";$in=$in."\r\n";#初始化回傳的內容$out = '';#如果連線到 socket 失敗if($socket_connect===false){#提示傳送HTTP HEAD中echo "Sending HTTP HEAD request...";}#if end#將訊息傳送到socket去socket_write($socket, $in, strlen($in));#如果連線到 socket 失敗if($socket_connect===false){#提示傳送完畢echo "OK.".PHP_EOL;#提示讀取回應中echo "Reading response:".PHP_EOL;}#if end#無窮迴圈while(true){#一次讀取2048bytes,判斷有無回應,並取得其內容.$out = socket_read($socket, 2048);#如果尚未取得 Sec-WebSocket-Acceptif(!isset($result["Sec-WebSocket-Accept"])){#如果連線到 socket 失敗if($socket_connect===false){#印出收到的內容echo $out;}#if end#如果 $out 有資料if($out){#如果接收到的是字串,且不為空if(gettype($out)==="string" && !empty($out)){#如果有既有的前次回應內容if(isset($result["content"])){#儲存回應的內容$result["content"]=$result["content"].$out;}#if end#反之else{#儲存回應的內容$result["content"]=$out;}#else end#涵式說明:#將固定格式的字串分開,並回傳分開的結果。#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["argu"],使用的參數.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填的參數:#$conf["stringIn"],字串,要處理的字串.$conf["stringProcess::spiltString"]["stringIn"]=$out;#$conf["spiltSymbol"],字串,爲以哪個符號作爲分割.$conf["stringProcess::spiltString"]["spiltSymbol"]="Sec-WebSocket-Accept: ";#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.$conf["stringProcess::spiltString"]["allowEmptyStr"]="false";$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果執行失敗if($spiltString["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$spiltString;#回傳結果return $result;}#if end#取得Sec-WebSocket-Accept$result["Sec-WebSocket-Accept"]=trim($spiltString["dataArray"][1]);#初始化要傳遞的內容$in="id?";#初始化傳遞的內容長度$len=strlen($in);#設置儲存每個元素為8bit字串的陣列$bit8=array();$bit8[0]="10000001";$bit8[1]="1".sprintf("%07s",base_convert($len,10,2));#mask key$bit8[2]="00000000";$bit8[3]="00000000";$bit8[4]="00000000";$bit8[5]="00000000";#mask key$mask_key=$bit8[2].$bit8[3].$bit8[4].$bit8[5];#針對每個字,進行maskfor($i=0;$i<$len;$i++){$j=$i%4;$in[$i]=$in[$i] xor $mask_key[$j];}#for end#如果連線到 socket 失敗if($socket_connect===false){#提示傳送資料echo "Sending Data...".PHP_EOL;}#if end#data frame$in=chr(base_convert($bit8[0],2,10)).chr(base_convert($bit8[1],2,10)).chr(base_convert($bit8[2],2,10)).chr(base_convert($bit8[3],2,10)).chr(base_convert($bit8[4],2,10)).chr(base_convert($bit8[5],2,10)).$in;#將訊息傳送到socket去socket_write($socket, $in, strlen($in));}#if end}#if end}#if end#反之取得了 Sec-WebSocket-Accept 就結束 HTTP/1.1else{#如果連線到 socket 失敗if($socket_connect===false){echo "解密前的內容:".PHP_EOL;}#if end#函式說明:#將字串中的每個字變成bytes陣列#回傳結果:#$result...#必填參數:#$conf["input"],字串,要轉換成bytes陣列的字串$conf["stringProcess::str2bytesArray"]["input"]=$out;#可省略參數:#無#建構中...$str2bytesArray=stringProcess::str2bytesArray($conf["stringProcess::str2bytesArray"]);unset($conf["stringProcess::str2bytesArray"]);#針對每個bytesforeach($str2bytesArray["content"] as $byte){#函式說明:#將bytes數字轉換為bit字串(0跟1來表述)#回傳結果:#$result...#必填參數:#$conf["input"],字串,要轉換成byte的字串$conf["stringProcess::str2bytesArray"]["bytes"]=$byte;#可省略參數:#無#建構中...$bytes2bitString=stringProcess::bytes2bitString($conf["stringProcess::str2bytesArray"]);unset($conf["stringProcess::str2bytesArray"]);#如果連線到 socket 失敗if($socket_connect===false){#debugvar_dump($bytes2bitString["content"]);}#if end}#foreach end#如果連線到 socket 失敗if($socket_connect===false){echo "解密後接收的內容:".PHP_EOL;}#if end#函式說明:#解密 handshake 後要接收的訊息#回傳結果:#$result["function"],當前函式的名稱.#$result["status"],執行結果狀態,"true"代表正常;"false"代表不正常.#$result["content"],unmask後的內容.#$result["type"],訊息的類型,"unknow":代表未定義;"text":代表為文字訊息;"pong":代表為pong;"invalid":代表不為web socket frame.#$result["error"],錯誤訊息陣列.#必填參數:#$conf["payload"],字串,要解密的訊息.$conf["webSock::unmask"]["payload"]=$out;#可省略參數:#$conf["allowUnmask"],字串,若發現沒有設置mask bit,也要繼續執行,則為"true";反之為"false".$conf["webSock::unmask"]["allowUnmask"]="true";#參考資料#http://www.inanzzz.com/index.php/post/swf8/converting-string-to-binary-and-binary-to-string-with-php#https://tools.ietf.org/html/rfc6455#https://tools.ietf.org/html/rfc5234#備註:#無.$unmask=webSock::unmask($conf["webSock::unmask"]);unset($conf["webSock::unmask"]);#如果執行失敗if($unmask["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$unmask;#回傳結果return $result;}#if end#記錄接收到的內容$received=$unmask["content"];#如果連線到 socket 失敗if($socket_connect===false){#debugvar_dump($received);}#if end}#else end#休息1秒sleep(1);}#while end#如果連線到 socket 失敗if($socket_connect===false){#提示關閉與 socket 的連線echo "Closing socket...";}#if end#關閉與 socket 的連線socket_close($socket);#如果連線到 socket 失敗if($socket_connect===false){#提示關閉連線成功echo "OK.".PHP_EOL;}#if end#設置執行正常$result["status"]="true";#回傳結果return $result;}#function clientDaemon end/*#函式說明:#webSocket的javaScript用戶端#回傳結果:#$result["status"],執行正常與否,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$resutl["function"],當前執行的涵式名稱.#$result["argu"],所使用的參數.#$result["content"],語法.#必填參數:#$conf["url"],字串要拜訪的web socket,請省略"ws://".$conf["url"]="";#可省略參數:#$conf["entry"],字串,是否要用加密的wss,預設為"false",代表用ws,若為"true"則為wss.#$conf["entry"]="false";#$conf["connVar"],字串,用來儲存webSocket連線的物件名稱,預設為"conn".#$conf["connVar"]="conn";#參考資料:#無.#備註:#無.*/public static function client(&$conf){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!=="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf===null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容。#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["function"],當前執行的函式名稱.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填寫的參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("url");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可以省略的參數:#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.$conf["variableCheck::checkArguments"]["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array();#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("entry","connVar");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string","string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("false","conn");#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料來源:#array_keys=>http://php.net/manual/en/function.array-keys.php#建議:#增加可省略參數全部不能為空字串或空陣列的參數功能.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果參數檢查不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#初始化 web socket 的協定$webSockUrl="ws://";#如果要加密if($conf["entry"]==="true"){$webSockUrl="wss://";}#if end#設置用戶端連線到webSocket的範例$script="<script>//建立 web socket 連線到 ".$webSockUrl.$conf["url"]."var ".$conf["connVar"]." = new WebSocket('".$webSockUrl.$conf["url"]."');//當連線成功後".$conf["connVar"].".onopen = function(e){//印出連線成功訊息到consoleconsole.log(\"Connection established!\");};//當有收到訊息時".$conf["connVar"].".onmessage = function(e) {//將訊息顯現在consoleconsole.log(e.data);};</script>";#設置建立webSocket連線的按鈕#函式說明:#放置按鈕#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["function"],當前執行的函數.#$result["error"],錯誤訊息陣列.#$result["content"],按鈕語法.#必要的參數:$conf["form::button"]["buttonDisplayValue"]="Send Hello!";#爲按鈕上顯示的文字。#可省略的參數:#$conf["buttonStyleName"]="";#可省略,爲按鈕所要使用的css樣式類別名稱,預設的css樣式爲 __simpleButtonLinkDefaultButtonCssStyle 。#其屬性爲 "width","height","font-size","text-align"#其屬性值爲 "100%" , "50" , "30" , "center"$conf["form::button"]["buttonActionScriptFunction"]="conn.send('Hello!');";#可省略,爲按下按鈕時所要執行的javaScript函式或程式,預設不設定。#"document.forms.formName.submit()"爲傳送名爲testForm的表單內容#"window.print()"爲使用瀏覽器內建工具列印當前網頁#若搭配 javaScript 類別的 confirmWindow 函數的回傳結果,則會有確認視窗的效果.#$conf["buttonBorder"]="";#可省略,爲IE9內會自動產生外框,此爲外框的厚度,屬性值爲正整數,預設爲0。#$conf["disabled"]="true";#可省略,為按鈕的功能是否要取消,若為"true"則代表要取消,若為"false"則代表功能正常,預設為"false".#$conf["tableStart"]="true";#爲是否要表格開始。"false"代表否,"true"代表是。預設爲"false"。#$conf["tableClass"]="";#表格要套用的css樣式,若省略的話,則預設爲 __defaultTbaleCsssStyle 其屬性爲 table-layout:fixed word-break:break-all width:100% ,須搭配 $conf["tablStart"] 與 $conf["tableEnd"] 使用。#$conf["trStart"]="true";#爲是否要以<tr>開頭,"true"表示"是"。也可以看作新的一列開始,預設為"false".#$conf["trClass"]="__withoutBorder";#<tr>要套用的css樣式,預設為"__withoutBorder",亦即沒有框線的樣式;"__withBorder"則爲有框線的樣式#$conf["tdStart"]="true";#爲是否要以<td>開頭,"true"表示"是"。也可以看成列裏面的元素開始,預設為"false".#$conf["tdClass"]="__withoutBorder";#<td>要套用的css樣式,"__withoutBorder"爲沒有框線的樣式;__withBorder爲有框線的樣式#$conf["tdEnd"]="true";#爲是否要以</td>結尾,"true"表示"是"。也可以看成列裏面的元素結束,預設為"false".#$conf["trEnd"]="true";#爲是否要以</tr>結尾,"true"表示"是"。也可以看作該列結束,預設為"false".#$conf["tableEnd"]="true";#爲是否要表格結束。"false"代表否,"true"代表是,預設爲"false"。#$conf["formStart"]="true";#爲是否要表單開始,如果爲"true"則代表要表單開始,預設為"false".#$conf["action"]="";#爲表單要傳送到哪個頁面,須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["target"]="";#為目標表單顯示的方式,若沒設定則預設爲"_self",其他可用的參數爲 "_blank"、"_parent"、"_top",也可以是iframe的名稱。須搭配$conf["formStart"]與$conf["formEnd"]參數使用#$conf["formEnd"]="true";#爲是否要表單結束,如果爲"true"則代表要表單結束,預設為"false".#$conf["formId"],字串,表單的id.#$conf["formId"]="";#$conf["buttonId"],字串,按鈕的id.#$conf["buttonId"]="";#參考資料來源:#http://stackoverflow.com/questions/3014649/how-to-disable-html-button-using-javascript$button=form::button($conf["form::button"]);unset($conf["form::button"]);#如果建立按鈕失敗if($button["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$button;#回傳結果return $result;}#if end#設置用戶端的html與js語法$result["content"]=$button["content"].$script;#設置執行正常$result["status"]="true";#回傳結果return $result;}#function client end/*#函式說明:#將 handshake 後含有 mask bit 的 web socket 訊息進行 mask/unmask.#回傳結果:#$result["function"],當前函式的名稱.#$result["argu"],使用的參數.#$result["status"],執行結果狀態,"true"代表正常;"false"代表不正常.#$result["content"],unmask後的內容.#$result["type"],訊息的類型,"unknow":代表未定義;"text":代表為文字訊息;"pong":代表為pong;"invalid":代表不為web socket frame.#$result["error"],錯誤訊息陣列.#必填參數:#$conf["payload"],字串,要解密的訊息.$conf["payload"]="";#可省略參數:$conf["allowUnmask"],字串,若發現沒有設置mask bit,也要繼續執行,則為"true";反之為"false".$conf["allowUnmask"]="false";#參考資料#http://www.inanzzz.com/index.php/post/swf8/converting-string-to-binary-and-binary-to-string-with-php#https://tools.ietf.org/html/rfc6455#https://tools.ietf.org/html/rfc5234#備註:#無.*/public static function mask(&$conf){#改呼叫 webSock::umaskreturn webSock::unmask($conf);}#function mask end/*#函式說明:#將 handshake 後含有 mask bit 的 web socket 訊息進行 mask/unmask.#回傳結果:#$result["function"],當前函式的名稱.#$result["argu"],使用的參數.#$result["status"],執行結果狀態,"true"代表正常;"false"代表不正常.#$result["content"],unmask後的內容.#$result["type"],訊息的類型,"unknow":代表未定義;"text":代表為文字訊息;"pong":代表為pong;"invalid":代表不為web socket frame.#$result["error"],錯誤訊息陣列.#必填參數:#$conf["payload"],字串,要解密的訊息.$conf["payload"]="";#可省略參數:#$conf["allowUnmask"],字串,若發現沒有設置mask bit,也要繼續執行,則為"true";反之為"false".#$conf["allowUnmask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料#http://www.inanzzz.com/index.php/post/swf8/converting-string-to-binary-and-binary-to-string-with-php#https://tools.ietf.org/html/rfc6455#https://tools.ietf.org/html/rfc5234#備註:#無.*/public static function unmask(&$conf) {#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#取得參數內容$result["argu"]=$conf;#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["simpleError"],簡單表示的錯誤訊息.#$result["function"],當前執行的函式名稱.#$result["argu"],設置給予的參數.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可省略參數:#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("payload");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null、any代表不指定變數形態.其中 resource也包含"resource (closed)".$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.#$conf["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array("allowUnmask","debug");#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("allowUnmask","debug");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string","string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("false","false");#$conf["disallowAllSkipableVarIsEmpty"],字串,是否允許每個可省略參數都為空字串,預設為"true"允許,反之為"false".#$conf["variableCheck::checkArguments"]["disallowAllSkipableVarIsEmpty"]="";#$conf["disallowAllSkipableVarIsEmptyArray"],字串,是否允許每個可省略參數都為空陣列,預設為"true"允許,反之為"false".#$conf["disallowAllSkipableVarIsEmptyArray"]="";#$conf["disallowAllSkipableVarNotExist"],字串,是否不允許每個可省略參數都不存在,預設為"false"代表允許,反之為"true".#$conf["disallowAllSkipableVarNotExist"]="";#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料:#array_keys=>http://php.net/manual/en/function.array-keys.php#備註:#無.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果檢查參數失敗if($checkArguments["status"]==="false"){#設置執行不正常$result["status"]="false";#設置錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果檢查參數不通過if($checkArguments["passed"]==="false"){#設置執行不正常$result["status"]="false";#設置錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#取得變數$payload=$conf["payload"];#如果要debugif($conf["debug"]==="true"){#debug payload lengthecho __LINE__." strlen(\$payload)=".strlen($payload).PHP_EOL;}#if end#web socket frame 最少為 2bytesif(strlen($payload)<2){#函式說明:#將字串中的每個字變成hex的字串陣列#回傳結果:#$result["status"],執行正常與否,"false"代表不正常,"true"代表正常.#$result["function"],當前執行的函式內容.#$result["error"],錯誤訊息陣列.#$result["content"],hex的字串陣列.#必填參數:#$conf["input"],字串,要轉換成bytes陣列的字串.$conf["stringProcess::str2bytesArray"]["input"]=$payload;#可省略參數:#無.#參考資料:#無.#備註:#無.$str2bytesArray=stringProcess::str2bytesArray($conf["stringProcess::str2bytesArray"]);unset($conf["stringProcess::str2bytesArray"]);#如果檢查參數失敗if($str2bytesArray["status"]==="false"){#設置執行不正常$result["status"]="false";#設置錯誤訊息$result["error"]=$str2bytesArray;#回傳結果return $result;}#if end#設置警告訊息$result["warning"][]="web socket frame 最少為 2 bytes,目前收到得為 ".strlen($payload)." bytes";#設置警告訊息$result["warning"][]="接收到的 web socket frame 內容";#設置警告訊息$result["warning"][]="(ASCII):".$payload;#開始截取輸出ob_start();#針對每個bytesfor($i=0;$i<count($str2bytesArray["content"]);$i++){#印出其內容echo "[".$str2bytesArray["content"][$i]."]";#若不是最後一個byteif($i===count($str2bytesArray["content"])-1){#空一格echo " ";}#if end}#if end#取得用HEX表示的內容$hexStr=ob_get_contents();#結束截取輸出ob_end_clean();#設置警告訊息$result["warning"][]="(HEX):".$hexStr;#設置為非 web socket frame$result["type"]="invalid";#設置執行正常$result["status"]="true";#回傳結果return $result;}#if end#如果要debugif($conf["debug"]==="true"){#debug data lengthecho __LINE__." \$length=".(ord($payload[1]) & 127).PHP_EOL;}#if end#取得字串長度$psl=strlen($payload);#初始化儲存每個bytes$bytes=array();#函式說明:#將字串中的每個字變成bytes陣列#回傳結果:#$result["status"],執行正常與否,"false"代表不正常,"true"代表正常.#$result["function"],當前執行的函式內容.#$result["error"],錯誤訊息陣列.#$result["content"],hex的字串陣列.#必填參數:#$conf["input"],字串,要轉換成bytes陣列的字串$conf["stringProcess::str2bytesArray"]["input"]=$payload;#可省略參數:#無$str2bytesArray=stringProcess::str2bytesArray($conf["stringProcess::str2bytesArray"]);unset($conf["stringProcess::str2bytesArray"]);#如果執行失敗if($str2bytesArray["status"]==="false"){#設置執行不正常$result["status"]="false";#設置錯誤訊息$result["error"]=$str2bytesArray;#回傳結果return $result;}#if end#針對每個bytesforeach($str2bytesArray["content"] as $bytesNum => $oneByte){#函式說明:#將bytes數字轉換為bit陣列(0跟1來表述)#回傳結果:#$result...#必填參數:#$conf["input"],字串,要轉換成byte的字串$conf["stringProcess::bytes2byte"]["bytes"]=$oneByte;#可省略參數:#無$bytes2byte=stringProcess::bytes2bitString($conf["stringProcess::bytes2byte"]);unset($conf["stringProcess::bytes2byte"]);#儲存bytes與其bit$bytes[$bytesNum]["content"]=$bytes2byte["content"];}#foreach end#frame-fin 1 bit#%x0 ; more frames of this message follow#%x1 ; final frame of this message$frameFin=$bytes[0]["content"][0];#如果不是最後一個 frameif($frameFin==="0"){#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." frame-fin = 0, not supported".PHP_EOL;}#if end#設置警告訊息$result["warning"][]="目前不支援大於一個frame的mask/unmask功能";#設置警告訊息$result["warning"][]=$bytes;#設置為非 web socket frame$result["type"]="invalid";#設置執行正常$result["status"]="true";#回傳結果return $result;}#if end#反之是最後一個 data frameelse{#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." frame-fin = 1, means this is a last data frame".PHP_EOL;}#if end}#else end#frame-rsv1 1 bit#MUST be 0 unless negotiated otherwise$frameRsv1=$bytes[0]["content"][1];#frame-rsv2 1 bit#MUST be 0 unless negotiated otherwise$frameRsv2=$bytes[0]["content"][2];#frame-rsv3 1 bit#MUST be 0 unless negotiated otherwise$frameRsv3=$bytes[0]["content"][3];#如果bit[1~3]都為0if($frameRsv1===$frameRsv2 && $frameRsv2===$frameRsv3 && $frameRsv3==="0"){#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." frame-rsv1~3 = 0".PHP_EOL;}#if end}#if end#如果不存在第5個bitif(!isset($bytes[0]["content"][4])){#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." $bytes[0]['content'][4] not set!".PHP_EOL;}#if end}#if end/*frame-opcode 4 bitframe-opcode-cont = %x0 ; frame continuationframe-opcode-non-control= %x1 ; text frame/ %x2 ; binary frame/ %x3-7; 4 bits in length,; reserved for further non-control framesframe-opcode-control = %x8 ; connection close/ %x9 ; ping/ %xA ; pong/ %xB-F ; reserved for further control; frames; 4 bits in length*/#如果 bytes[0] 長度不足 8if(gettype($bytes[0]["content"])==="array"){if(count($bytes[0]["content"])!==8){#$i為4~7for($i=4;$i<8;$i++){#如果未設置if(!isset($bytes[0]["content"][$i])){#用 "0" 去補$bytes[0]["content"][$i]="0";}#if end}#for end}#if end}#if end$frameOpcode=$bytes[0]["content"][4].$bytes[0]["content"][5].$bytes[0]["content"][6].$bytes[0]["content"][7];#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." frame-opcode = ".$frameOpcode.PHP_EOL;}#if end$frameOpcodeIntX=$bytes[0]["content"][4]*pow(2,3)+$bytes[0]["content"][5]*pow(2,2)+$bytes[0]["content"][6]*pow(2,1)+$bytes[0]["content"][7]*pow(2,0);#設置預設訊息類型為 unknow$result["type"]="unknow";#如果 Opcode 等於 1if($frameOpcodeIntX===1){#如果要debugif($conf["debug"]==="true"){#debugecho "It is a text frame".PHP_EOL;}#if end#設置該訊息類型為 text$result["type"]="text";}#if end#如果 Opcode 等於 9else if($frameOpcodeIntX===9){#如果要debugif($conf["debug"]==="true"){#debugecho "It is a ping frame".PHP_EOL;}#if end#設置該訊息類型為 text$result["type"]="ping";}#if end#如果是 pongelse if($frameOpcodeIntX===10){#如果要debugif($conf["debug"]==="true"){#debugecho "It is a pong frame".PHP_EOL;}#if end#設置該訊息類型為 pong$result["type"]="pong";}#if end#frame-masked 1 bit#%x0 ;frame is not masked, no frame-masking-key#%x1 ;frame is masked, frame-masking-key present 1 bit in lengt$frameMasked=$bytes[1]["content"][0];#預設收到的訊息有mask過.$masked=true;#如果沒有 maskedif($frameMasked!=='1'){#如果不允許沒有設置 masked bitif($conf["allowUnmask"]!=="true"){#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." frame-masked !== 1, differ with https://tools.ietf.org/html/rfc6455#section-5.3".PHP_EOL;}#if end#設置為非 web socket frame$result["type"]="invalid";#設置執行正常$result["status"]="true";#回傳結果return $result;}#if end#設置收到的訊息沒有mask過.$masked=false;}#if end#debug#echo __LINE__." frame-masked = ".$frameMasked.PHP_EOL;#frame-payload-length 7 bit, 7+16 bits, or 7+64 bits/*The length of the "Payload data", in bytes: if 0-125, that is thepayload length. If 126, the following 2 bytes interpreted as a16-bit unsigned integer are the payload length. If 127, thefollowing 8 bytes interpreted as a 64-bit unsigned integer (themost significant bit MUST be 0) are the payload length. Multibytelength quantities are expressed in network byte order. Note thatin all cases, the minimal number of bytes MUST be used to encodethe length, for example, the length of a 124-byte-long stringcan't be encoded as the sequence 126, 0, 124. The payload lengthis the length of the "Extension data" + the length of the"Application data". The length of the "Extension data" may bezero, in which case the payload length is the length of the"Application data".*/if(gettype($bytes[1]["content"])==="array"){if(count($bytes[1]["content"])!==8){#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." payloadLengthBit length !== 8".PHP_EOL;}#if end#如果 bit 不存在,用 0 補上for($i=1;$i<8;$i++){#如果未設置if(!isset($bytes[1]["content"][$i])){#用"0"替代$bytes[1]["content"][$i]="0";}#if end}#for end#代表是用戶在連線.#return "client connected!";}#if end}#if end$payloadLengthBit=$bytes[1]["content"][1].$bytes[1]["content"][2].$bytes[1]["content"][3].$bytes[1]["content"][4].$bytes[1]["content"][5].$bytes[1]["content"][6].$bytes[1]["content"][7];#length from 0~127(0~125)$payloadLength=$bytes[1]["content"][7]*pow(2,0)+$bytes[1]["content"][6]*pow(2,1)+$bytes[1]["content"][5]*pow(2,2)+$bytes[1]["content"][4]*pow(2,3)+$bytes[1]["content"][3]*pow(2,4)+$bytes[1]["content"][2]*pow(2,5)+$bytes[1]["content"][1]*pow(2,6);#如果長度小於 126if($payloadLength<126){#mask bit start bytes index$maskBitStartBytesIndex=2;#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." mask bit start bytes index = ".$maskBitStartBytesIndex.PHP_EOL;}#if end}#if end#如果長度是 126if($payloadLength===126){$payloadLengthBit=$bytes[2]["content"][0].$bytes[2]["content"][1].$bytes[2]["content"][2].$bytes[2]["content"][3].$bytes[2]["content"][4].$bytes[2]["content"][5].$bytes[2]["content"][6].$bytes[2]["content"][7].$bytes[3]["content"][0].$bytes[3]["content"][1].$bytes[3]["content"][2].$bytes[3]["content"][3].$bytes[3]["content"][4].$bytes[3]["content"][5].$bytes[3]["content"][6].$bytes[3]["content"][7];#初始化 payload 長度$payloadLength=0;#2次迴圈,兩個bytesfor($i=0;$i<2;$i++){#8次迴圈,1個byte等於8個bitfor($j=0;$j<8;$j++){#次方數$k=$j+8*$i;#加總 payload 長度$payloadLength=$payloadLength+$bytes[3-$i]["content"][7-$j]*pow(2,$k);}#for end}#for end#mask bit start bytes index$maskBitStartBytesIndex=4;#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." mask bit start bytes index = ".$maskBitStartBytesIndex.PHP_EOL;}#if end}#if end#如果長度是 127else if($payloadLength===127){$payloadLengthBit="";#四次迴圈(4個bytes)for($i=0;$i<4;$i++){#8次迴圈,1個byte等於8個bitfor($j=0;$j<8;$j++){$payloadLengthBit=$payloadLengthBit.$bytes[4+$i]["content"][0+$j];}#for end}#for end#初始化 payload 長度$payloadLength=0;#四次迴圈(4個bytes)for($i=0;$i<4;$i++){#8次迴圈,1個byte等於8個bitfor($j=0;$j<8;$j++){#次方數$k=$j+8*$i;$payloadLength=$payloadLength+$bytes[7-$i]["content"][7-$j]*pow(2,$k);}#for end}#for end#mask bit start bytes index$maskBitStartBytesIndex=8;#如果要debugif($conf["debug"]==="true"){#debugecho __LINE__." mask bit start bytes index = ".$maskBitStartBytesIndex.PHP_EOL;}#if end}#if end#如果要debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$bytes);#debug 提示payload的長度的2進位表示法echo __LINE__." payload data payloadLengthBit is ".$payloadLengthBit.PHP_EOL;#debug 提示payload的長度echo __LINE__." payload data length is ".$payloadLength." bytes".PHP_EOL;}#if end#如果有maskif($masked){#組合 maskBit 字串$maskBitStr=chr(base_convert($bytes[$maskBitStartBytesIndex]["content"],2,10)).chr(base_convert($bytes[$maskBitStartBytesIndex+1]["content"],2,10)).chr(base_convert($bytes[$maskBitStartBytesIndex+2]["content"],2,10)).chr(base_convert($bytes[$maskBitStartBytesIndex+3]["content"],2,10));#如果要debugif($conf["debug"]==="true"){#debug 提示 mask bit 字串echo __LINE__." maskBit str is ".$maskBitStr.PHP_EOL;}#if end}#if end#初始化 payload data 字串$payloadDataStr="";#如果有maskif($masked){#有多長就跑幾次for($i=0;$i<$payloadLength;$i++){#串接 masked 的 payload data.$payloadDataStr=$payloadDataStr.chr(base_convert($bytes[$maskBitStartBytesIndex+4+$i]["content"],2,10));}#for end#如果要debugif($conf["debug"]==="true"){#debug 提示 mask bit 字串echo __LINE__." masked payload data str is ".$payloadDataStr.PHP_EOL;}#if end#unmask payload datafor($i=0;$i<$payloadLength;$i++){$payloadDataStr[$i]=$payloadDataStr[$i]^$maskBitStr[$i%4];}#for end}#if end#反之else{#有多長就跑幾次for($i=0;$i<$payloadLength;$i++){#串接 masked 的 payload data.$payloadDataStr=$payloadDataStr.chr(base_convert($bytes[$maskBitStartBytesIndex+$i]["content"],2,10));}#for end}#else end#取得 umask 後的內容$result["content"]=$payloadDataStr;#設置執行正常$result["status"]="true";#回傳結果return $result;}#function unmask end/*#函式說明:#加密 handshake 後要傳送的 webSocket 訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["text"]="";#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["payloadIsBin"]="false";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#https://www.rfc-editor.org/rfc/rfc6455#page-28, Web Socket Base Framing Protocol.#備註:#無.*/public static function encode(&$conf){#初始化要回傳的結果$result=array();#設置當其函數名稱$result["function"]=__FUNCTION__;#初始化分割好的 web socket 封包$result["content"]=array();#如果 $conf 不為陣列if(gettype($conf)!="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif($conf==null){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end}#if end#設置放置的參數$result["argu"]=$conf;#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$reuslt["error"],執行不正常結束的錯訊息陣列.#$result["simpleError"],簡單表示的錯誤訊息.#$result["function"],當前執行的函式名稱.#$result["argu"],設置給予的參數.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可省略參數:#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("text");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null代表不指定變數形態.$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string");#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.#$conf["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array("payloadIsBin","ping","pong","mask","debug");#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("payloadIsBin","ping","pong","frames","mask","debug");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string","string","string","array","string","string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array("false","false","false",array(),"false","false");#$conf["disallowAllSkipableVarIsEmpty"],字串,是否允許每個可省略參數都為空字串,預設為"true"允許,反之為"false".$conf["variableCheck::checkArguments"]["disallowAllSkipableVarIsEmpty"]="false";#$conf["disallowAllSkipableVarIsEmptyArray"],字串,是否允許每個可省略參數都為空陣列,預設為"true"允許,反之為"false".#$conf["disallowAllSkipableVarIsEmptyArray"]="";#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料:#array_keys=>http://php.net/manual/en/function.array-keys.php#備註:#無.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#如果執行失敗if($checkArguments["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果參數檢查不通過if($checkArguments["passed"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$checkArguments;#回傳結果return $result;}#if end#如果是要產生 ping/pong 的訊息if($conf["ping"]==="true" || $conf["pong"]==="true"){#強制將payload設置為空$conf["text"]="";}#if end#取得payload$text=$conf["text"];#取得 payload length$length=strlen($text);#如果沒有payloadif($length===0){#初始化第一個 frame 為 最後一個 frame.$header="1000";#如果是pingif($conf["ping"]==="true"){#其訊息類別為 ping$header=$header."1001";}#if end#如果是pongelse if($conf["pong"]==="true"){#其訊息類別為 pong$header=$header."1010";}#if end#例外狀況else{#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="參數 text 為空時,需要 ping or pong 參數擇一";#設置執行錯誤訊息$result["error"][]=$checkArguments;#回傳結果return $result;}#else end}#if end#反之有payloadelse{#初始化第一個 frame 為 最後一個 frame.$header="1000";#如果 payload 是 2元碼if($conf["payloadIsBin"]==="true"){#設置 opecode 為 0010$header=$header."0010";}#if end#反之為 textelse{#設置 opecode 為 0001$header=$header."0001";}#else end}#else end#如果 payload 長度大於 125while($length > 125){#初始化第一個 frame 為 不為最後一個 frame,$header="0000";#如果 payload 是 2元碼if($conf["payloadIsBin"]==="true"){#設置 opecode 為 0010$header=$header."0010";}#if end#反之為 textelse{#設置 opecode 為 0001$header=$header."0001";}#else end#如果已經有前面的內容了if(count($result["content"])>0){#設置為中間的 frame, 其 opcode 為 continue data.$header="00000000";}#if end#取得125bytes$body=substr($text,0,125);#函式說明:#將2進位的8位數字字串,變成bytes字串.#回傳結果:#$result["status"],執行正常與否,"false"代表不正常,"true"代表正常.#$result["function"],當前執行的函式內容.#$result["error"],錯誤訊息陣列.#$result["content"],bytes字串,亦即其代表的一個字.#必填參數:#$conf["8bits"],字串,要轉換成byte字串的bit數字字串,小於8位會於前頭補0,若非2進位的bit數字字串,則會報錯.$conf["stringProcess::bit2byteStr"]["8bits"]=$header;#可省略參數:#無.#參考資料:#無.#備註:#無.$bit2byteStr=stringProcess::bit2byteStr($conf["stringProcess::bit2byteStr"]);unset($conf["stringProcess::bit2byteStr"]);#如果執行失敗if($bit2byteStr["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$bit2byteStr;#回傳結果return $result;}#if end#取得該 byte 字串$headerInByte=$bit2byteStr["content"];#預設不用mask$maskBitAndLengthIntString=(string)(125);#如果需要maskif($conf["mask"]==="true"){$maskBitAndLengthIntString=(string)(125+128);}#if end#函式說明:#將2進位的8位數字字串,變成bytes字串.#回傳結果:#$result["status"],執行正常與否,"false"代表不正常,"true"代表正常.#$result["function"],當前執行的函式內容.#$result["error"],錯誤訊息陣列.#$result["content"],bytes字串,亦即其代表的一個字.#必填參數:#$conf["8bits"],字串,要轉換成byte字串的bit數字字串,小於8位會於前頭補0,若非2進位的bit數字字串,則會報錯.$conf["stringProcess::bit2byteStr"]["8bits"]=base_convert($maskBitAndLengthIntString,10,2);#可省略參數:#無.#參考資料:#無.#備註:#無.$bit2byteStr=stringProcess::bit2byteStr($conf["stringProcess::bit2byteStr"]);unset($conf["stringProcess::bit2byteStr"]);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$bit2byteStr);}#if end#如果執行失敗if($bit2byteStr["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$bit2byteStr;#回傳結果return $result;}#if end#取得該 byte 字串$lengthInByte=$bit2byteStr["content"];#初始化 4 bytes mask key.$maskKey4bytes="";#如果需要maskif($conf["mask"]==="true"){#函式說明:#隨機產生任意byte(s)組成的字串.#回傳結果:#$result["status"],執行正常與否,"false"代表不正常,"true"代表正常.#$result["function"],當前執行的函式內容.#$result["error"],錯誤訊息陣列.#$result["content"],用字串來表示的byte(s).#必填參數:#無.#可省略參數:#$conf["length"],字串,要產生多少bytes的字串,預設為1.$conf["stringProcess::randomByte"]["length"]="4";#參考資料:#無.#備註:#無.$randomByte=stringProcess::randomByte($conf["stringProcess::randomByte"]);unset($conf["stringProcess::randomByte"]);#如果執行失敗if($randomByte["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$randomByte;#回傳結果return $result;}#if end#取得隨機產生的 mask key$maskKey4bytes=$randomByte["content"];#函式說明:#將 handshake 後含有 mask bit 的 web socket 訊息進行 mask/unmask.#回傳結果:#$result["function"],當前函式的名稱.#$result["argu"],使用的參數.#$result["status"],執行結果狀態,"true"代表正常;"false"代表不正常.#$result["content"],unmask後的內容.#$result["type"],訊息的類型,"unknow":代表未定義;"text":代表為文字訊息;"pong":代表為pong;"invalid":代表不為web socket frame.#$result["error"],錯誤訊息陣列.#必填參數:#$conf["payload"],字串,要解密的訊息.$conf["webSock::unmask"]["payload"]=$headerInByte.$lengthInByte.$maskKey4bytes.$body;#可省略參數:#$conf["allowUnmask"],字串,若發現沒有設置mask bit,也要繼續執行,則為"true";反之為"false".$conf["webSock::unmask"]["allowUnmask"]="true";#參考資料#http://www.inanzzz.com/index.php/post/swf8/converting-string-to-binary-and-binary-to-string-with-php#https://tools.ietf.org/html/rfc6455#https://tools.ietf.org/html/rfc5234#備註:#無.$unmask=webSock::unmask($conf["webSock::unmask"]);unset($conf["webSock::unmask"]);#debug#var_dump(__LINE__,$unmask);#如果執行失敗if($unmask["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$unmask;#回傳結果return $result;}#if end#取得該段的結果$result["content"][]=$headerInByte.$lengthInByte.$maskKey4bytes.$unmask["content"];}#if end#反之else{#取得該段的結果$result["content"][]=$headerInByte.$lengthInByte.$maskKey4bytes.$body;}#else end#取得剩下的內容$text=substr($text,125);#取得 payload length$length=strlen($text);}#while end#執行到這邊代表剩下的長度用一個 frame 即可表達#如果已經有內容了if(count($result["content"])>0){#代表不用表示為 text frame 但要表示為最後一個 frame.$header="10000000";}#if end#函式說明:#將2進位的8位數字字串,變成bytes字串.#回傳結果:#$result["status"],執行正常與否,"false"代表不正常,"true"代表正常.#$result["function"],當前執行的函式內容.#$result["error"],錯誤訊息陣列.#$result["content"],bytes字串,亦即其代表的一個字.#必填參數:#$conf["8bits"],字串,要轉換成byte字串的bit數字字串,小於8位會於前頭補0,若非2進位的bit數字字串,則會報錯.$conf["stringProcess::bit2byteStr"]["8bits"]=$header;#可省略參數:#無.#參考資料:#無.#備註:#無.$bit2byteStr=stringProcess::bit2byteStr($conf["stringProcess::bit2byteStr"]);unset($conf["stringProcess::bit2byteStr"]);#如果執行失敗if($bit2byteStr["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$bit2byteStr;#回傳結果return $result;}#if end#取得該 byte 字串$headerInByte=$bit2byteStr["content"];#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$length,base_convert($length,10,2));}#if end#如果需要maskif($conf["mask"]==="true"){#增加maskbit$length=$length+128;}#if end#函式說明:#將2進位的8位數字字串,變成bytes字串.#回傳結果:#$result["status"],執行正常與否,"false"代表不正常,"true"代表正常.#$result["function"],當前執行的函式內容.#$result["error"],錯誤訊息陣列.#$result["content"],bytes字串,亦即其代表的一個字.#必填參數:#$conf["8bits"],字串,要轉換成byte字串的bit數字字串,小於8位會於前頭補0,若非2進位的bit數字字串,則會報錯.$conf["stringProcess::bit2byteStr"]["8bits"]=base_convert($length,10,2);#可省略參數:#無.#參考資料:#無.#備註:#無.$bit2byteStr=stringProcess::bit2byteStr($conf["stringProcess::bit2byteStr"]);unset($conf["stringProcess::bit2byteStr"]);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$bit2byteStr);}#if end#如果執行失敗if($bit2byteStr["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$bit2byteStr;#回傳結果return $result;}#if end#取得該 byte 字串$lengthInByte=$bit2byteStr["content"];#初始化 4 bytes mask key.$maskKey4bytes="";#如果需要maskif($conf["mask"]==="true"){#函式說明:#隨機產生任意byte(s)組成的字串.#回傳結果:#$result["status"],執行正常與否,"false"代表不正常,"true"代表正常.#$result["function"],當前執行的函式內容.#$result["error"],錯誤訊息陣列.#$result["content"],用字串來表示的byte(s).#必填參數:#無.#可省略參數:#$conf["length"],字串,要產生多少bytes的字串,預設為1.$conf["stringProcess::randomByte"]["length"]="4";#參考資料:#無.#備註:#無.$randomByte=stringProcess::randomByte($conf["stringProcess::randomByte"]);unset($conf["stringProcess::randomByte"]);#如果執行失敗if($randomByte["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$randomByte;#回傳結果return $result;}#if end#取得隨機產生的 mask key$maskKey4bytes=$randomByte["content"];}#if end#函式說明:#將 handshake 後含有 mask bit 的 web socket 訊息進行 mask/unmask.#回傳結果:#$result["function"],當前函式的名稱.#$result["argu"],使用的參數.#$result["status"],執行結果狀態,"true"代表正常;"false"代表不正常.#$result["content"],unmask後的內容.#$result["type"],訊息的類型,"unknow":代表未定義;"text":代表為文字訊息;"pong":代表為pong;"invalid":代表不為web socket frame.#$result["error"],錯誤訊息陣列.#必填參數:#$conf["payload"],字串,要解密的訊息.$conf["webSock::unmask"]["payload"]=$headerInByte.$lengthInByte.$maskKey4bytes.$text;#可省略參數:#$conf["allowUnmask"],字串,若發現沒有設置mask bit,也要繼續執行,則為"true";反之為"false".$conf["webSock::unmask"]["allowUnmask"]="true";#參考資料#http://www.inanzzz.com/index.php/post/swf8/converting-string-to-binary-and-binary-to-string-with-php#https://tools.ietf.org/html/rfc6455#https://tools.ietf.org/html/rfc5234#備註:#無.$unmask=webSock::unmask($conf["webSock::unmask"]);unset($conf["webSock::unmask"]);#如果要 debugif($conf["debug"]==="true"){#debugvar_dump(__LINE__,$unmask);}#if end#如果執行失敗if($unmask["status"]==="false"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]=$unmask;#回傳結果return $result;}#if end#儲存訊息$result["content"][]=$headerInByte.$lengthInByte.$maskKey4bytes.$unmask["content"];#設置執行正常$result["status"]="true";#回傳結果return $result;}#function encode end/*函式說明:提供webSock::nativeSocketTcpIpServer的processFuncs參數所用的函式,可以接受要求傳遞檔案的內容給用戶.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常,"continue"代表不適用.#$result["error"],執行不正常結束的錯訊息陣列.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["data"],字串,收到的json格式資料,必填的key有"Method","Host","File",Method的value目前只支援"GET",Host的value為ServerName亦即網站的網域,File為要求的檔案路徑與名稱;可省略的key有"Range"跟"partSize"跟id,Range的value為需要的檔案內容範圍,目前只支援"bytes=n1-n2"的格式,partSize的value為取得檔案的分段大小,預設為1024000(bytes),亦即1MB,id為用於給用戶端識別的id.$conf["data"]="";#$conf["serverSock"],resource,web socket server socket$conf["serverSock"]=$resource;#$conf["clientSock"],$resource,web socket client socket$conf["clientSock"]=$resource;#$conf["clientInfo"],陣列,web socket client info.$conf["clientInfo"]=array();#$conf["clientIndex"],整數.web socket client index.$conf["clientIndex"];#$conf["allConn"],陣列,all web socket client info.$conf["allConn"]=array();#可省略參數:#無.#參考資料:#https://www.rfc-editor.org/rfc/rfc6455#page-28, Web Socket Base Framing Protocol.#備註:#無.*/public static function getFileContent(&$conf){#初始化要回傳的結果$result=array();#取得當前執行的函數名稱$result["function"]=__FUNCTION__;#如果沒有參數if(func_num_args()==0){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"]="函數".$result["function"]."需要參數";#回傳結果return $result;}#if end#涵式說明:#判斷當前環境為web還是cmd#回傳結果:#$result,"web"或"cmd"if(csInformation::getEnv()==="web"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="函數 ".$result["function"]." 僅能在命令列環境下運行!";#回傳結果return $result;}#if end#取得參數$result["argu"]=$conf;#如果 $conf 不為陣列if(gettype($conf)!=="array"){#設置執行失敗$result["status"]="false";#設置執行錯誤訊息$result["error"][]="\$conf變數須為陣列形態";#如果傳入的參數為 nullif(is_null($conf)){#設置執行錯誤訊息$result["error"][]="\$conf變數不得為null,請檢查函數「".$result["function"]."」的參數設置有無正確!";}#if end#回傳結果return $result;}#if end#debug#var_dump(__FUNCTION__,__LINE__,$conf);#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["simpleError"],簡單表示的錯誤訊息.#$result["function"],當前執行的函式名稱.#$result["argu"],設置給予的參數.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$conf;#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可省略參數:#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("data","serverSock","clientSock","clientInfo","clientIndex","allConn");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null、any代表不指定變數形態.其中 resource也包含"resource (closed)".$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string","resource","resource","array","integer","array");#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.$conf["variableCheck::checkArguments"]["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.#$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array("Range","partSize");#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");#$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("Range","partSize");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");#$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string","partSize");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".#$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array(null,"1024000");#$conf["disallowAllSkipableVarIsEmpty"],字串,是否允許每個可省略參數都為空字串,預設為"true"允許,反之為"false".#$conf["disallowAllSkipableVarIsEmpty"]="";#$conf["disallowAllSkipableVarIsEmptyArray"],字串,是否允許每個可省略參數都為空陣列,預設為"true"允許,反之為"false".#$conf["disallowAllSkipableVarIsEmptyArray"]="";#$conf["disallowAllSkipableVarNotExist"],字串,是否不允許每個可省略參數都不存在,預設為"false"代表允許,反之為"true".#$conf["disallowAllSkipableVarNotExist"]="";#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料:#array_keys=>http://php.net/manual/en/function.array-keys.php#備註:#無.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#debug#var_dump(__FUNCTION__,__LINE__,$checkArguments);#如果執行失敗if($checkArguments["status"]==="false"){#設置錯誤訊息$result["error"]=$checkArguments;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#如果檢查不通過if($checkArguments["passed"]==="false"){#不處理,略過,交給下個 processFuncs 處理$result["status"]="continue";#回傳結果return $result;}#if end#檢查收到的訊息是否為json格式$revJson=@json_decode($conf["data"]);#如果不是 jsonif($revJson===null){#不處理,略過,交給下個 processFuncs 處理$result["status"]="continue";#回傳結果return $result;}#if enf#轉換為陣列$revJson=(array)($revJson);#檢查參數#函式說明:#檢查必填與可省略的參數,可省略參數可指定預設要給與什麼數值內容.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["simpleError"],簡單表示的錯誤訊息.#$result["function"],當前執行的函式名稱.#$result["argu"],設置給予的參數.#$result["passed"],識別要檢查的全體變數是否存在以及型態是否正確的變數,"true"代表檢查全部通過;"false"代表檢查不通過#$result[$shouldBeCheckedVarName]["varExist"],所檢查的變數是否存在,"false"代表不存在;"true"代表存在#$result[$shouldBeCheckedVarName]["varType"],所檢查的變數型態是否正確,"false"代表錯誤;"true"代表正確#$result[$shouldBeCheckedVarName]["error"],每個參數設定的錯誤訊息#$result["shouldNotBeEmpty"],不應該為空字串或控陣列的變數.#$result["argu"],字串陣列,目前輸入的參數名稱陣列.#$result["legalVarName"],字串陣列,合法可用的參數名稱陣列.#$result["notNeedVar"],字串陣列,多餘的參數名稱.#必填參數:#$conf["varInput"],陣列變數,要檢查的陣列變數,請在要檢查的參數前面加上&,這樣變動的結果才能被套用。$conf["variableCheck::checkArguments"]["varInput"]=&$revJson;#$conf["referenceVarKey"],字串,$conf參數後面的key值,用於移除不要的參考陣列.$conf["variableCheck::checkArguments"]["referenceVarKey"]="variableCheck::checkArguments";#可省略參數:#$conf["mustBeFilledVariableName"],爲必填參數的變數名稱陣列,形態爲陣列變數,元素數量需要跟"mustBeFilledVariableType"參數的元素數量一致,例如: $conf["mustBeFilledVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["mustBeFilledVariableName"]=array("Method","Host","File");#$conf["mustBeFilledVariableType"],爲必填參數的變數陣列應該爲何種變數形態,形態爲陣列,元素數量需要跟"mustBeFilledVariableName"參數的元素數量一致,例如: $conf["mustBeFilledVariableType"] = array("string",integer,"double","resource","object"); , null、any代表不指定變數形態.其中 resource也包含"resource (closed)".$conf["variableCheck::checkArguments"]["mustBeFilledVariableType"]=array("string","string","string");#$conf["canBeEmptyString"],字串,必填變數內容如果是空字串就不能算是有設置的話,請設為"false",預設爲"true",可以為空字串.$conf["variableCheck::checkArguments"]["canBeEmptyString"]="false";#$conf["canNotBeEmpty"],字串陣列,哪些必填參數的內容不得為空字串或空陣列,僅當$conf["canBeEmptyString"]為"true"時會生效.#$conf["canNotBeEmpty"]=array();#$conf["canBeEmpty"],字串陣列,哪些必填參數的內容可為空字串或空陣列,僅當$conf["canBeEmptyString"]為"false"時會生效.#$conf["canBeEmpty"]=array();#$conf["skipableVariableCanNotBeEmpty"],字串陣列,哪些可省略參數不可以為空字串或空陣列.$conf["variableCheck::checkArguments"]["skipableVariableCanNotBeEmpty"]=array("id","Range","partSize");#$conf["skipableVariableName"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableName"] = array("id","account","password");$conf["variableCheck::checkArguments"]["skipableVariableName"]=array("id","Range","partSize");#$conf["skipableVariableType"],陣列字串,爲可省略參數的變數名稱陣列,形態爲陣列變數,例如: $conf["skipableVariableType"] = array("string",integer,"double");$conf["variableCheck::checkArguments"]["skipableVariableType"]=array("string","string","string");#$conf["skipableVarDefaultValue"],字串陣列,每個不存在的可省略變數要初始化為什麼,null與代表不指定,若預設值是參數之一,請將$conf["mustBeFilledVar"]改成"\$conf["\mustBeFilledVar\"]".$conf["variableCheck::checkArguments"]["skipableVarDefaultValue"]=array(null,null,"1024000");#$conf["disallowAllSkipableVarIsEmpty"],字串,是否允許每個可省略參數都為空字串,預設為"true"允許,反之為"false".#$conf["disallowAllSkipableVarIsEmpty"]="";#$conf["disallowAllSkipableVarIsEmptyArray"],字串,是否允許每個可省略參數都為空陣列,預設為"true"允許,反之為"false".#$conf["disallowAllSkipableVarIsEmptyArray"]="";#$conf["disallowAllSkipableVarNotExist"],字串,是否不允許每個可省略參數都不存在,預設為"false"代表允許,反之為"true".#$conf["disallowAllSkipableVarNotExist"]="";#$conf["arrayCountEqualCheck"],字串陣列,為檢查哪些陣列參數的元素數量要一樣,$conf["arrayCountEqualCheck"][$i]=array()為第$i組key為哪些的變數其元素數量要相等.#$conf["arrayCountEqualCheck"][]=array();#參考資料:#array_keys=>http://php.net/manual/en/function.array-keys.php#備註:#無.$checkArguments=variableCheck::checkArguments($conf["variableCheck::checkArguments"]);unset($conf["variableCheck::checkArguments"]);#debug#var_dump(__FUNCTION__,__LINE__,$checkArguments);#如果執行失敗if($checkArguments["status"]==="false"){#設置錯誤訊息$result["error"]=$checkArguments;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#如果檢查不通過if($checkArguments["passed"]==="false"){#不處理,略過,交給下個 processFuncs 處理$result["status"]="continue";#回傳結果return $result;}#if end#如果是 GET Methodif($revJson["Method"]==="GET"){#解析 apache vhost info#函式說明:#使用 linux 的 httpd 指令來取得 vhost 資訊.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息.#$result["function"],當前執行的函式名稱.#$result["content"],得到的結果陣列,每個元素可能會含有的key有ServerName、DocumentRoot、ServerAlias,其中DocumentRoot的數值會是用""包起來的路徑.#必填參數:#$conf["fileArgu"],字串,php變數__FILE__的內容,亦即該檔案在檔案系統的絕對路徑$conf["cmd::httpdGetVhostInfo"]["fileArgu"]=__FILE__;#可省略參數:#無.#參考資料:#無#備註:#無.$httpdGetVhostInfo=cmd::httpdGetVhostInfo($conf["cmd::httpdGetVhostInfo"]);unset($conf["cmd::httpdGetVhostInfo"]);#debug#var_dump(__FUNCTION__,__LINE__,$httpdGetVhostInfo);#如果執行失敗if($httpdGetVhostInfo["status"]==="false"){#設置錯誤訊息$result["error"]=$httpdGetVhostInfo;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#針對每個結果foreach($httpdGetVhostInfo["content"] as $vhost){#如果有 ServerNameif(isset($vhost["ServerName"])){#如果是要找的 Hostif($vhost["ServerName"]===$revJson["Host"]){#如果有 DocumentRootif(isset($vhost["DocumentRoot"])){#組合要取得的檔案路徑與名稱$file=$vhost["DocumentRoot"]."/".$revJson["File"];#debug#var_dump(__LINE__,$file);#如果有 Range 參數if(isset($revJson["Range"])){#格式參考#bytes=0-499#函式說明:#將字串特定關鍵字與其前面的內容剔除#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列.#$result["warning"],警告訊息鎮列.#$result["founded"],有無找到定字串"true"代表有,"false"代表沒有.#$result["function"],當前執行的函數名稱.#$result["argu"],使用的參數.#$result["oriStr"],要處理的原始字串內容.#$result["content"],處理好的的字串內容.#必填參數:#$conf["stringIn"],字串,要處理的字串.$conf["stringProcess::delStrBeforeKeyWord"]["stringIn"]=$revJson["Range"];#$conf["keyWord"],字串,特定字串.$conf["stringProcess::delStrBeforeKeyWord"]["keyWord"]="bytes=";#可省略參數:#$conf["recursive"],字串,預設為"false"代表找到一個關鍵字就會停止;"true"代表會即重複執行,知道沒有關鍵字為止.#$conf["recursive"]="true";#$conf["lastResult"],陣列,本函式前次執行的結果,若沒有找到關鍵字,則會改回傳該內容.#$conf["lastResult"]=$delStrBeforeKeyWord;#參考資料:#無.#備註:#無.$delStrBeforeKeyWord=stringProcess::delStrBeforeKeyWord($conf["stringProcess::delStrBeforeKeyWord"]);unset($conf["stringProcess::delStrBeforeKeyWord"]);#如果執行失敗if($delStrBeforeKeyWord["status"]==="false"){#設置錯誤訊息$result["error"]=$delStrBeforeKeyWord;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#如果沒有該有的關鍵字if($delStrBeforeKeyWord["founded"]==="false"){#設置錯誤訊息$result["error"]=$delStrBeforeKeyWord;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#解析 bytes start and end#函式說明:#將固定格式的字串分開,並回傳分開的結果.#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],錯誤訊息陣列#$result["function"],當前執行的函數名稱.#$result["argu"],使用的參數.#$result["oriStr"],要分割的原始字串內容#$result["dataArray"],爲分割好字串的陣列內容,$result["dataArray"][$i]爲第($i+1)段的內容。#$result["dataCounts"],爲總共分成幾段#$result["found"],是否有在$conf["stringIn"]找到$conf["spiltSymbol"],"true"代表有找到,"false"代表沒有找到.#必填參數:#$conf["stringIn"],字串,要處理的字串.$conf["stringProcess::spiltString"]["stringIn"]=$delStrBeforeKeyWord["content"];#$conf["spiltSymbol"],字串,爲以哪個符號作爲分割.$conf["stringProcess::spiltString"]["spiltSymbol"]="-";#可省略參數:#$conf["allowEmptyStr"],是否允許分割出來空字串,預設為"false"不允許;"true"代表允許.#$conf["allowEmptyStr"]="false";#參考資料:#無.#備註:#無.$spiltString=stringProcess::spiltString($conf["stringProcess::spiltString"]);unset($conf["stringProcess::spiltString"]);#如果執行失敗if($spiltString["status"]==="false"){#設置錯誤訊息$result["error"]=$spiltString;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#如果沒有應該有的 - 符號if($spiltString["found"]==="false"){#設置錯誤訊息$result["error"]=$spiltString;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#如果沒有分割成2段if($spiltString["dataCounts"]!==2){#設置錯誤訊息$result["error"]=$spiltString;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#依照Range來取得檔案內容#函式說明:#取得檔案的部分內容#回傳結果:#$result["status"],"true"代表移除成功,"false"代表移除失敗.#$result["error"],錯誤訊息陣列.#$result["function"],當前執行的函數名稱.#$result["cmd"],執行的指令.#$result["content"],取得的檔案內容.#$result["length"],取得的內容長度.#$result["EOF"],識別是否已經到檔案結尾,"true"代表是,"false"代表不是.#$result["mimeType"],檔案的 mime type.#必填參數:#$conf["file"],字串,檔案的路徑與名稱.$conf["fileAccess::getFilePart"]["file"]=$file;#$conf["fileArgu"],字串,__FILE__的內容.$conf["fileAccess::getFilePart"]["fileArgu"]=__FILE__;#$conf["bytes"],整數字串,要讀取多少bytes.$conf["fileAccess::getFilePart"]["bytes"]=$spiltString["dataArray"][1]-$spiltString["dataArray"][0]+1;#$conf["startIndex"],要從哪個bytes位置開始,起始點為0.$conf["fileAccess::getFilePart"]["startIndex"]=$spiltString["dataArray"][0];#可省略參數:#無#參考資料:#無.#備註:#無$getFilePart=fileAccess::getFilePart($conf["fileAccess::getFilePart"]);unset($conf["fileAccess::getFilePart"]);#如果執行失敗if($getFilePart["status"]==="false"){#設置錯誤訊息$result["error"]=$getFilePart;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#初始化要傳遞的訊息$msg=array();#設置為最後一份了$msg["LastPart"]="true";#設置資料內容類型為binary$msg["dataType"]="binary";#設置內容$msg["content"]=$getFilePart["content"];#設置 mimeType$msg["mimeType"]=$getFilePart["mimeType"];#如果有設置 idif(isset($revJson["id"])){#設置資料的 id$msg["id"]=$revJson["id"];}#if end#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=base64_encode(urlencode(json_encode($msg)));#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["webSock::encode"]["payloadIsBin"]="true";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["webSock::encode"]["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#無.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#針對每個訊息的分段foreach($talkback["content"] as $msg){#回傳訊息$socket_write=socket_write($conf["clientSock"], $msg, strlen($msg));#如果傳遞訊息給用戶失敗if($socket_write===false){#取得錯誤代碼$errorCode=socket_last_error($conf["clientSock"]);#設置執行失敗$result["status"]="false";#設置錯誤代碼$result["error"][]="error code:".$errorCode;#設置錯誤代碼說明$result["erorr"][]="error description:".socket_strerror($errorCode);#回傳結果return $result;}#if end}#foreach end#設置正常,結束後面函式的執行$result["status"]="true";#回傳結果return $result;}#if end#反之沒有 Rnage 參數else{#執行到這邊代表要取得全部的檔案內容#debug#var_dump(__LINE__,"get full file content");#第一部分的編號$partNo=0;#無窮迴圈while(true){#分段取得檔案#函式說明:#取得檔案的部分內容#回傳結果:#$result["status"],"true"代表移除成功,"false"代表移除失敗.#$result["error"],錯誤訊息陣列.#$result["function"],當前執行的函數名稱.#$result["cmd"],執行的指令.#$result["content"],取得的檔案內容.#$result["length"],取得的內容長度.#$result["EOF"],識別是否已經到檔案結尾,"true"代表是,"false"代表不是.#$result["mimeType"],檔案的 mime type.#必填參數:#$conf["file"],字串,檔案的路徑與名稱.$conf["fileAccess::getFilePart"]["file"]=$file;#$conf["fileArgu"],字串,__FILE__的內容.$conf["fileAccess::getFilePart"]["fileArgu"]=__FILE__;#$conf["bytes"],整數字串,要讀取多少bytes.$conf["fileAccess::getFilePart"]["bytes"]=$revJson["partSize"];#$conf["startIndex"],要從哪個bytes位置開始,起始點為0.$conf["fileAccess::getFilePart"]["startIndex"]=$partNo*$revJson["partSize"];#可省略參數:#無#參考資料:#無.#備註:#無$getFilePart=fileAccess::getFilePart($conf["fileAccess::getFilePart"]);unset($conf["fileAccess::getFilePart"]);#debug#var_dump(__LINE__,$getFilePart);#如果執行失敗if($getFilePart["status"]==="false"){#設置錯誤訊息$result["error"]=$getFilePart;#var_dump,交給下個 processFuncs 處理$result["status"]="false";#回傳結果return $result;}#if end#初始化要傳遞的訊息$msg=array();#設置不為最後一份$msg["LastPart"]="false";#設置資料內容類型為binary$msg["dataType"]="binary";#設置內容$msg["content"]=$getFilePart["content"];#設置 mimeType$msg["mimeType"]=$getFilePart["mimeType"];#如果有設置 idif(isset($revJson["id"])){#設置資料的 id$msg["id"]=$revJson["id"];}#if end#如果偵測到檔案結尾if($getFilePart["EOF"]==="true"){#設置為最後一份了$msg["LastPart"]="true";#如果沒有內容if($getFilePart["length"]===0){#檔案區塊數字-1$partNo--;}#if end#傳遞給 client - start#編碼後的訊息$msgEncoded=base64_encode(urlencode(json_encode($msg)));#debug#var_dump(__LINE__,$msg,$msgEncoded);#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=$msgEncoded;#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["webSock::encode"]["payloadIsBin"]="false";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["webSock::encode"]["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#無.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#debug#var_dump(__LINE__,$talkback);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#針對每個訊息的分段foreach($talkback["content"] as $msg){#回傳訊息$socket_write=socket_write($conf["clientSock"], $msg, strlen($msg));#debug#var_dump(__LINE__,$socket_write,$msg);#如果傳遞訊息給用戶失敗if($socket_write===false){#取得錯誤代碼$errorCode=socket_last_error($conf["clientSock"]);#設置執行失敗$result["status"]="false";#設置錯誤代碼$result["error"][]="error code:".$errorCode;#設置錯誤代碼說明$result["erorr"][]="error description:".socket_strerror($errorCode);#回傳結果return $result;}#if end}#foreach end#傳遞給 client - end#結束 whilebreak;}#if end#傳遞給 client - start#debug#var_dump(__LINE__,"start tranfer");#函式說明:#加密 handshake 後要傳送的訊息#回傳結果:#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.#$result["error"],執行不正常結束的錯訊息陣列.#$result["content"],陣列,加密 handshake 後要傳送給 client 的訊息,若有多個代表要分為多個 Fragmentation 來依序傳送.#$result["argu"],陣列,使用的參數.#必填參數:#$conf["text"],字串,要加密的訊息.$conf["webSock::encode"]["text"]=base64_encode(urlencode(json_encode($msg)));#可省略參數:#$conf["payloadIsBin"],字串,"true"定義Payload data是為2元碼;預設為"false"代表為文字.#$conf["webSock::encode"]["payloadIsBin"]="true";#$conf["ping"],字串,"true"代表為ping訊息;反之為"false",預設為"false".#$conf["ping"]="false";#$conf["pong"],字串,"true"代表為pong訊息;反之為"false",預設為"false".#$conf["pong"]="false";#$conf["frames"],陣列,目前既有的訊息frame,預設為空陣列,代表沒有.#$conf["frames"]=array();#$conf["mask"],字串,代表是否要將內容進行mask,預設為"false",代表不要,適用於server to client;反之為"true"代表要,適用於client to server.#$conf["webSock::encode"]["mask"]="false";#$conf["debug"],字串,"true"代表要show debug訊息;反之為預設"false".#$conf["debug"]="false";#參考資料:#無.#備註:#無.$talkback=webSock::encode($conf["webSock::encode"]);unset($conf["webSock::encode"]);#如果執行失敗if($talkback["status"]==="false"){#印出結果var_dump($talkback);#結束執行exit;}#if end#針對每個訊息的分段foreach($talkback["content"] as $msg){#回傳訊息$socket_write=socket_write($conf["clientSock"], $msg, strlen($msg));#如果傳遞訊息給用戶失敗if($socket_write===false){#取得錯誤代碼$errorCode=socket_last_error($conf["clientSock"]);#設置執行失敗$result["status"]="false";#設置錯誤代碼$result["error"][]="error code:".$errorCode;#設置錯誤代碼說明$result["erorr"][]="error description:".socket_strerror($errorCode);#回傳結果return $result;}#if end}#foreach end#傳遞給 client - end#檔案區塊數字+1$partNo++;}#while end#設置執行正常$result["status"]="true";#回傳結果return $result;}#else end}#if end}#if end}#if end}#foreach end#設置執行不正常$result["status"]="false";#設置執行錯誤$result["error"]="no matched ServerName";#debugvar_dump(__FUNCTION__,__LINE__,$result);#回傳結果return $result;}#if end#設置執行不正常$result["status"]="false";#設置執行錯誤$result["error"]="Method should be GET";#回傳結果return $result;}#function getFileContent end}#class webSock end?>