前回の記事からの続きです。
ユーザーはテキスト形式で保存され、ユーザー配列はjsonエンコードされます。
リーリー
フォルダーとファイルの許可手順:
リーリー
実装コードは次のとおりです:
クラスユーザー{ const I = 1; //継承 const FD = 2; //フォルダー削除 const FN = 4; //フォルダーの名前を変更 const FC = 8; //フォルダー作成 const FL = 16; //フォルダーリスト const D = 32; //ファイル削除 const N = 64; //ファイル名変更 const A = 128; //ファイル追加 const W = 256; //ファイル書き込み(アップロード) const R = 512; //ファイル読み取り(ダウンロード) プライベート $hash_salt = ''; プライベート $user_file; プライベート $group_file; プライベート $users = array(); プライベート $groups = array(); プライベート $file_hash = ''; パブリック 関数 __construct(){ $this->user_file = BASE_PATH.'/conf/users'; $this->group_file = BASE_PATH.'/conf/groups'; $this->reload(); } /** * 戻り权制限表达式 * @param int $access * @戻り文字列 */ パブリック 静的 関数 AC($access){ $str = ''; $char = array('R','W','A','N','D','L','C','N','D','I' ); for($i = 0; $i $i++){ if($access & pow(2,9-$i))$str.= $char[$i];else $str.= 「-」; } リターン $str; } /** * 追加用户データ */ パブリック 関数 reload(){ $user_file_hash = md5_file($this->user_file); $group_file_hash = md5_file($this->group_file); if($this->file_hash != md5($user_file_hash.$group_file_hash)){ if(($user = file_get_contents($this->user_file)) !== false){ $this->users = json_decode($user,true); if($this->ユーザー){ //folder排序 foreach ($this->ユーザー as $user=>$profile){ if(isset($profile['フォルダ'])){ $this->users[$user]['folder'] = $this->sortFolder($profile['folder']); } } } }if(($group = file_get_contents($this->group_file)) !== false){ $this->groups = json_decode($group,true); if($this->グループ){ //folder排序 foreach ($this->グループ as $group=>$profile){ if(isset($profile['フォルダ'])){ $this->groups[$group]['フォルダー'] = $this->sortFolder($profile['フォルダー']); } } } } $this->file_hash = md5($user_file_hash.$group_file_hash); } } /** *对フォルダ行排序 * @return 配列 */ プライベート 関数 sortFolder($folder){ uasort($フォルダー, 関数($a,$b){ return strnatcmp($a['path'], $b['path']); }); $result = array(); foreach ($フォルダー as $v){ $結果[] = $v; } リターン $結果; } /** *保存用户データ */ パブリック 関数 save(){ file_put_contents($this->user_file, json_encode($this->users),LOCK_EX); file_put_contents($this->グループファイル, json_encode($this->グループ),LOCK_EX); } /** * 添加用户 * @param 文字列 $user * @param 文字列 $pass * @param 文字列 $home * @param string $expired * @param boolean $active * @param 文字列 $group * @param string $description * @param string $email * @return ブール値 */ public function addUser($user,$pass,$home,$expired,$active=true,$group='',$description= '',$email = ''){ $user = strto lower($user); if(isset($this->users[$user]) || 空($user)){ 戻る false; } $this->users[$user] = array( 'パス' => md5($user.$this->hash_salt.$pass), 'ホーム' => $ホーム、 '期限切れ' => $期限切れ、 'アクティブ' => $アクティブ、 'グループ' => $グループ、 '説明' => $説明、 '電子メール' => $メール、 ); 戻る 本当; } /** * 設置用户費 * @param 文字列 $user * @param 配列 $profile * @return ブール値 */ public function setUserProfile($user,$profile){ $user = strto lower($user); if(is_array($profile) && isset($this->users[$user])){ if(isset($profile['pass'])){ $profile['pass'] = md5($user.$this->hash_salt.$profile['pass']); }if(isset($profile['active'])){ if(!is_bool($profile['active'])){ $profile['active'] = $profile['active'] == 'true' ? 真:偽; } } $this->users[$user] = array_merge($this->users[$user],$profile); 戻る 本当; } 戻る false; } /** *获取用户资料 * @param 文字列 $user * @return multitype:|boolean */ パブリック 関数 getUserProfile($user){ $user = strto lower($user); if(isset($this->ユーザー[$user])){ return $this->users[$user]; } 戻る false; } /** *删除用户 * @param 文字列 $user * @return ブール値 */ パブリック 関数 delUser($user){ $user = strto lower($user); if(isset($this->ユーザー[$user])){ 設定解除($this->ユーザー[$user]); 戻る 本当; } 戻る false; } /** * 获取用户列表 * @return 配列 */ パブリック 関数 getUserList(){ $list = array(); if($this->ユーザー){ foreach ($this->ユーザー as $user=>$profile){ $list[] = $user; } } 並べ替え($リスト); 戻る $リスト; } /** * 添加組 * @param 文字列 $group * @param 文字列 $home * @return ブール値 */ パブリック 関数 addGroup($group,$home){ $group = strto lower($group); if(isset($this->グループ[$group])){ 戻る false; } $this->グループ[$グループ] = 配列( 'ホーム' => $ホーム ); 戻る 本当; } /** * 設置費 * @param 文字列 $group * @param 配列 $profile * @return ブール値 */ public function setGroupProfile($group,$profile){ $group = strto lower($group); if(is_array($profile) && isset($this->groups[$group])){ $this->グループ[$グループ] = array_merge($this->グループ[$グループ],$プロファイル); 戻る 本当; } 戻る false; } /** *获取组资料 * @param 文字列 $group * @return multitype:|boolean */ パブリック 関数 getGroupProfile($group){ $group = strto lower($group); if(isset($this->グループ[$group])){ 戻る $this->グループ[$グループ]; } 戻る false; }/** * グループの削除 * @param 文字列 $group * @return ブール値 */ パブリック 関数 delGroup($group){ $group = strto lower($group); if(isset($this->グループ[$group])){ 設定解除($this->グループ[$group]); foreach ($this->ユーザーas $user => $profile){ if($profile['グループ'] == $グループ) $this->ユーザー[$user]['グループ'] = ''; } 戻る 本当; } 戻る false; } /** * グループリストを取得する * @return 配列 */ パブリック 関数 getGroupList(){ $list = array(); if($this->グループ){ foreach ($this->グループas $group=>$profile){ $リスト[] = $グループ; } } 並べ替え($リスト); 戻る $リスト; } /** * グループユーザーリストの取得 * @param 文字列 $group * @return 配列 */ パブリック 関数 getUserListOfGroup($group){ $list = array(); if(isset($this->グループ[$グループ]) && $this->ユーザー){ foreach ($this->ユーザー as $user=>$profile){ if(isset($profile['グループ']) && $profile['グループ'] == $グループ){ $list[] = $user; } } } 並べ替え($リスト); 戻る $リスト; } /** * ユーザ認証 * @param 文字列 $user * @param 文字列 $pass * @パラメータ文字列$ip * @return ブール値 */ public function checkUser($user,$pass,$ip = ''){ $this->reload(); $user = strto lower($user); if(isset($this->ユーザー[$user])){ if($this->users[$user]['active'] && time() strtotime($this->users[$user) ][「期限切れ」]) && $this->users[$user]['pass'] == md5($user.$this->hash_salt.$pass)){ if(空($ip)){ 戻る 本当; }他{ //IP認証 return $this->checkIP($user, $ip); } }他{ 戻る false; } } 戻る false; }/** * 基本認証 * @パラメータ文字列$base64 */ パブリック 関数 checkUserBasicAuth($base64){ $base64 = trim(str_replace('Basic ', '', $base64)); $str = base64_decode($base64); if($str !== false){ list($user,$pass) = explode(':', $str,2); $this->reload(); $user = strto lower($user); if(isset($this->ユーザー[$user])){ $group = $this->users[$user]['グループ']; if($group == 'admin' && $this->users[$user]['active'] && time() <= strtotime($this ->ユーザー[$user]['期限切れ']) && $this->users[$user]['pass'] == md5($user.$this->hash_salt.$pass)){ 戻る 本当; }他{ 戻る false; } } } 戻る false; } /** * 用户登录ip验证 * @param 文字列 $user * @パラメータ文字列$ip * * ユーザの IP 制限は、承認グループの IP 制限に従います。* マッチングルール: * 1. グループ許可リストの照合を実行します。 * 2. 合格したかのように、グループ拒否リストのマッチングを実行します。 * 3. ユーザー権限の照合を実行します。 * 4. 合格した場合、ユーザー拒否マッチングを実行します。 * */ パブリック 関数 checkIP($user,$ip){ $pass = false; //最初にグループ認証を実行します $group = $this->users[$user]['グループ']; //グループでマッチングが可能です if(isset($this->グループ[$group]['ip']['allow'])){ foreach ($this->groups[$group]['ip']['allow'] as $addr){ $pattern = '/'.str_replace('*','d+',str_replace('.', '.', $addr)).'/'; if(preg_match($pattern, $ip) && !empty($addr)){ $pass = true; 休憩; } } } //許可されている場合は、マッチングを拒否します if($pass){ if(isset($this->グループ[$group]['ip']['deny'])){ foreach ($this->groups[$group]['ip']['deny'] as $addr){ $pattern = '/'.str_replace('*','d+',str_replace('.', '.', $addr)).'/'; if(preg_match($pattern, $ip) && !empty($addr)){ $pass = false; 休憩; } } } } if(isset($this->users[$user]['ip']['allow'])){ foreach ($this->users[$user]['ip']['allow'] as $addr){ $pattern = '/'.str_replace('*','d+',str_replace('.', '.', $addr)).'/'; if(preg_match($pattern, $ip) && !empty($addr)){ $pass = true; 休憩; } } } if($pass){ if(isset($this->users[$user]['ip']['deny'])){ foreach ($this->users[$user]['ip']['deny'] as $addr){ $pattern = '/'.str_replace('*','d+',str_replace('.', '.', $addr)).'/'; if(preg_match($pattern, $ip) && !empty($addr)){ $pass = false; 休憩; } } } } echo date('Y-m-d H:i:s')." [debug]tIP ACCESS:".' '.($pass?'true':'false')."n"; リターン $pass; } /** * ユーザーのホームディレクトリを取得します * @param 文字列 $user * @戻り文字列 */ パブリック 関数 getHomeDir($user){ $user = strto lower($user); $group = $this->users[$user]['グループ']; $dir = ''; if($グループ){ if(isset($this->グループ[$group]['home']))$dir = $this->グループ[$group][ 「家」]; }$dir = !empty($this->users[$user]['home'])?$this->users[$user]['home' ]:$ディレクトリ; return $dir; } //文件权限界判断 public function isReadable($user,$path){ $result = $this->getPathAccess($user, $path); if($result['isExactMatch']){ return $result['access'][0] == 'R'; }他{ return $result['access'][0] == 'R' && $result['access'][9] == 'I'; } } public function isWritable($user,$path){ $result = $this->getPathAccess($user, $path); if($result['isExactMatch']){ return $result['access'][1] == 'W'; }他{ return $result['access'][1] == 'W' && $result['access'][9] == 'I'; } } public function isAppendable($user,$path){ $result = $this->getPathAccess($user, $path); if($result['isExactMatch']){ return $result['access'][2] == 'A'; }他{ return $result['access'][2] == 'A' && $result['access'][9] == 'I'; } } public function isRenamable($user,$path){ $result = $this->getPathAccess($user, $path); if($result['isExactMatch']){ return $result['access'][3] == 'N'; }他{ return $result['access'][3] == 'N' && $result['access'][9] == 'I'; } } public function isDeletable($user,$path){ $result = $this->getPathAccess($user, $path); if($result['isExactMatch']){ return $result['access'][4] == 'D'; }他{ return $result['access'][4] == 'D' && $result['access'][9] == 'I'; } } //目录权限界判断 public function isFolderListable($user,$path){ $result = $this->getPathAccess($user, $path); if($result['isExactMatch']){ return $result['access'][5] == 'L'; }他{ return $result['access'][5] == 'L' && $result['access'][9] == 'I'; } } public function isFolderCreatable($user,$path){ $result = $this->getPathAccess($user, $path); if($result['isExactMatch']){ return $result['access'][6] == 'C'; }他{ return $result['access'][6] == 'C' && $result['access'][9] == 'I'; } }public function isFolderRenamable($user,$path){ $result = $this->getPathAccess($user, $path); if($result['isExactMatch']){ return $result['access'][7] == 'N'; }他{ return $result['access'][7] == 'N' && $result['access'][9] == 'I'; } } public function isFolderDeletable($user,$path){ $result = $this->getPathAccess($user, $path); if($result['isExactMatch']){ return $result['access'][8] == 'D'; }他{ return $result['access'][8] == 'D' && $result['access'][9] == 'I'; } } /** *获取目录权制限 * @param 文字列 $user * @param 文字列 $path * @return 配列 * 最长路径適合を実行します * * 戻り: * 配列( * 'access'=>目前权制限 * ,'isExactMatch'=>否か精确適合 * * ); * *如果精确適合、则忽略継承。 * 否则应判断是否继承父目录的权限, * 权制限位表: * +---+---+---+---+---+---+---+---+---+---+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | * +---+---+---+---+---+---+---+---+---+---+ * | R | W |あ | N | D | L | C | N | D |私 | * +---+---+---+---+---+---+---+---+---+---+ * | ファイル | フォルダ | * +-------------------+-------------------+ */ パブリック 関数 getPathAccess($user,$path){ $this->reload(); $user = strto lower($user); $group = $this->users[$user]['グループ']; //削除文書名 $path = str_replace(substr(strrchr($path, '/'),1),'',$path); $access = self::AC(0); $isExactMatch = false; if($グループ){ if(isset($this->グループ[$グループ]['フォルダー'])){ foreach ($this->groups[$group]['folder'] as $f){ //中文处理 $t_path = iconv('UTF-8','GB18030',$f['パス']); if(strpos($path, $t_path) === 0){ $access = $f['access']; $isExactMatch = ($path == $t_path?true:false); } } } } if(isset($this->users[$user]['folder'])){ foreach ($this->users[$user]['folder'] as $f){ //中文处理 $t_path = iconv('UTF-8','GB18030',$f['パス']); if(strpos($path, $t_path) === 0){ $access = $f['access']; $isExactMatch = ($path == $t_path?true:false); } } } echo date('Y-m-d H:i:s')." [debug]tACCESS:$access ".' '.($isExactMatch?'1':'0')." $pathn"; return array('access'=>$access,'isExactMatch'=>$isExactMatch); }/** * 追加在中用 * @param ShareMemory $shm * @param swoole_server $serv * @param 不明な $user * @param 不明 $fd * @param 不明な $ip * @return Ambigous
これは比較的簡単で、php の shmop 拡張機能を使用するだけです。
クラス ShareMemory{ プライベート $mode = 0644; プライベート $shm_key; プライベート $shm_size; /** *构造関数数 */ パブリック 関数 __construct(){ $key = 'F'; $サイズ = 1024*1024; $this->shm_key = ftok(__FILE__,$key); $this->shm_size = $size + 1; } /** *读取内存数组 * @return 配列|ブール値 */ パブリック 関数 read(){ if(($shm_id = shmop_open($this->shm_key,'c',$this->モード,$this->shm_size)) !== false ){ $str = shmop_read($shm_id,1,$this->shm_size-1); shmop_close($shm_id); if(($i = strpos($str," ")) !== false)$str = substr($str,0,$i ); if($str){ return json_decode($str,true); }他{ return array(); } } 戻る false; } /** * 写量组到内存 * @param 配列 $arr * @return int|boolean */ パブリック 関数 write($arr){ if(!is_array($arr))return false; $str = json_encode($arr)." "; if(strlen($str) > $this->shm_size) return false; if(($shm_id = shmop_open($this->shm_key,'c',$this->モード,$this->shm_size)) !== false ){ $count = shmop_write($shm_id,$str,1); shmop_close($shm_id); 戻る $count; } 戻る false; } /** * 删除内保存块、次回使用時に再新开辟内保存块 * @return ブール値 */ パブリック 関数 delete(){ if(($shm_id = shmop_open($this->shm_key,'c',$this->モード,$this->shm_size)) !== false ){ $result = shmop_delete($shm_id); shmop_close($shm_id); リターン $結果; } 戻る false; } } コードを表示
クラス CWebServer{ 保護 $buffer_header = array(); 保護 $buffer_maxlen = 65535; //最大POSTサイズ const DATE_FORMAT_HTTP = 'D, d-M-Y H:i:s T'; const HTTP_EOF = "rnrn"; const HTTP_HEAD_MAXLEN = 8192; // http ヘッダーの最大長は 2k を超えてはなりません const HTTP_POST_MAXLEN = 1048576;//1m const ST_FINISH = 1; //完了、処理フローに入ります const ST_WAIT = 2 //データを待っています; const ST_ERROR = 3; //エラー、このパッケージを破棄します プライベート $requsts = array(); プライベート $config = array(); public function log($msg,$level = 'デバッグ'){ echo date('Y-m-d H:i:s').' ['.$level."]t" .$msg."n"; } public function __construct($config = array()){ $this->config = array( 'wwwroot' => __DIR__.'/wwwroot/', 'インデックス' => 'インデックス.php', 'path_deny' => 配列('/protected/'), ); } public function onReceive($serv,$fd,$data){ $ret = $this->checkData($fd, $data); スイッチ ($ret){ ケース self::ST_ERROR: $serv->close($fd); $this->cleanBuffer($fd); $this->log('受信エラー。'); 休憩; ケース self::ST_WAIT: $this->log('受信はお待ちください。'); 戻る; デフォルト: 休憩; } //完全なリクエストを開始します $request = $this->リクエスト[$fd]; $info = $serv->connection_info($fd); $request = $this->parseRequest($request); $request['remote_ip'] = $info['remote_ip']; $response = $this->onRequest($request); $output = $this->parseResponse($request,$response); $serv->send($fd,$output); if(isset($request['head']['Connection']) && strto lower($request['head']['Connection']) == 'close' ){ $serv->close($fd); } 設定解除($this->リクエスト[$fd]); $_REQUEST = $_SESSION = $_COOKIE = $_FILES = $_POST = $_SERVER = $_GET = array() ; }/** *处理请求 * @param 配列 $request * @return array $response * * $リクエスト=配列( * '時間'=> * 'head'=>配列( * 'メソッド'=> * 'パス'=> * 'プロトコル'=> * 'uri'=> * //その他の http ヘッダー * '..'=>値 *) * '本体'=> * 'get'=>(該当する場合) * 'post'=>(該当する場合) * 'cookie'=>(該当する場合) * * *) */ パブリック 関数 onRequest($request){ if($request['head']['path'][strlen($request['head']['path']) - 1] == '/'){ $request['head']['path'] .= $this->config['index']; } $response = $this->プロセス($request); リターン $レスポンス; } /** * 消去データ * @param 不明 $fd */ パブリック 関数 cleanBuffer($fd){ 設定解除($this->リクエスト[$fd]); 設定解除($this->buffer_header[$fd]); } /** * 检查データ * @param 不明 $fd * @param 不明な $data * @戻り文字列 */ パブリック 関数 checkData($fd,$data){ if(isset($this->buffer_header[$fd])){ $data = $this->buffer_header[$fd].$data; } $request = $this->checkHeader($fd, $data); //请求头错误 if($request === false){ $this->buffer_header[$fd] = $data; if(strlen($data) > self::HTTP_HEAD_MAXLEN){ return self::ST_ERROR; }他{ return self::ST_WAIT; } } //投稿请求检查 if($request['head']['method'] == 'POST'){ return $this->checkPost($request); }他{ return self::ST_FINISH; } } /** *检查请求头 * @param 不明 $fd * @param 不明な $data * @return ブール値|配列 */ public function checkHeader($fd, $data){ //新しい依頼 if(!isset($this->requsts[$fd])){ //http头结束符 $ret = strpos($data,self::HTTP_EOF); if($ret === false){ 戻る false; }他{ $this->buffer_header[$fd] = ''; $request = array(); list($header,$request['body']) = explode(self::HTTP_EOF, $data,2); $request['head'] = $this->parseHeader($header); $this->リクエスト[$fd] = $リクエスト; if($request['head'] == false){ 戻る false; } } }他{ //ポストデータマージ $request = $this->リクエスト[$fd]; $request['body'] .= $data; } 返却 $リクエスト; } /** * リクエストヘッダーを解析する * @param string $header * @return 配列 * 配列( * 'メソッド'=>, * 'uri'=> * 'プロトコル'=> * '名前'=>値,... * * * * } */ public function parseHeader($header){ $request = array(); $headlines = explode("rn", $header); list($request['メソッド'],$request['uri'],$request['プロトコル']) = explode(' ', $headlines[0] ,3); foreach ($見出し as $k=>$line){ $line = トリム($line); if($k && !空($line) && strpos($line,':') !== false){ list($name,$value) = explode(':', $line,2); $request[trim($name)] = trim($value); } } 返却 $リクエスト; } /** ※投稿データが揃っているか確認してください * @param 不明な $request * @戻り文字列 */ パブリック 関数 checkPost($request){ if(isset($request['head']['Content-Length'])){ if(intval($request['head']['Content-Length']) > self::HTTP_POST_MAXLEN){ return self::ST_ERROR; } if(intval($request['head']['Content-Length']) > strlen($request['body'])){ return self::ST_WAIT; }他{ return self::ST_FINISH; } } return self::ST_ERROR; } /** * リクエストを解析する * @param 不明な $request * @return 曖昧な