先说下原理:因为视频是付费的,肯定需要作视频加密处理。
加密可实现的方式:修改视频字节流,只能替换字节流,例如头100-1024字节进行加密,源文件就无法打开了。
下面上代码吧,加解密是
openssl_encrypt
openssl_decrypt
<?php /** * * Created by PhpStorm. * User: js * Date: 2021/04/15 * Time: 17:03 * PhpStorm */ namespace CoreModelPayfilms; class Movie{ const KEY = 'jiangsheng'; const METHOD = 'des-ecb'; static function movieModify($filename){ $strLong = mt_rand(1,9); $str = self::randStr($strLong); // 字符串占位 $key = self::randStr(6); // key $Pkey = base64_encode($key); $fp = fopen($filename, 'r+') or die('文件打开失败!'); $bin = fread($fp, $strLong); //随机 $passStr = self::_encrypt($bin,$key); // 密文头 转存 // 判断是否是小写字母组成 $i = 0; while (!feof($fp)) { //修改第二行数据 if ($i == 0) { fseek($fp, 0);// 移动文件指针至偏移量处 fwrite($fp, $str); break; } fgets($fp); $i++; } fclose($fp); return [ 'key'=>$key, 'Pkey'=>$Pkey, 'passStr'=>$passStr, 'str'=>$str, 'bin'=>$bin ]; } static function movieReduction($filename, $passStr, $Pkey){ $fp = fopen($filename, 'r+') or die('文件打开失败!'); $key = base64_decode($Pkey); $str = self::_decrypt($passStr,$key); $i = 0; while (!feof($fp)) { //修改第二行数据 if ($i == 0) { fseek($fp, 0);// 移动文件指针至偏移量处 fwrite($fp,$str); break; } fgets($fp); $i++; } fclose($fp); return true; } static function handOpen($filename){ $fp = fopen($filename, 'r') or die('文件打开失败!'); $content = fread($fp, filesize($filename)); return $content; } static function _encrypt($data, $key=self::KEY, $method=self::METHOD){ return openssl_encrypt($data, $method, $key); } static function _decrypt($data, $key=self::KEY, $method=self::METHOD){ return openssl_decrypt($data, $method, $key); } static function authcode($string,$key='',$operation=false,$expiry=0){ $ckey_length = 4; $key = md5($key ? $key : self::KEY); $keya = md5(substr($key, 0, 16)); $keyb = md5(substr($key, 16, 16)); $keyc = $ckey_length ? ($operation? substr($string, 0, $ckey_length):substr(md5(microtime()), -$ckey_length)) : ''; $cryptkey = $keya.md5($keya.$keyc); $key_length = strlen($cryptkey); $string = $operation? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string; $string_length = strlen($string); $result = ''; $box = range(0, 255); $rndkey = array(); for($i = 0; $i <= 255; $i++) { $rndkey[$i] = ord($cryptkey[$i % $key_length]); } for($j = $i = 0; $i < 256; $i++) { $j = ($j + $box[$i] + $rndkey[$i]) % 256; $tmp = $box[$i]; $box[$i] = $box[$j]; $box[$j] = $tmp; } for($a = $j = $i = 0; $i < $string_length; $i++) { $a = ($a + 1) % 256; $j = ($j + $box[$a]) % 256; $tmp = $box[$a]; $box[$a] = $box[$j]; $box[$j] = $tmp; $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256])); } if($operation) { if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) { return substr($result, 26); } else { return ''; } } else { return $keyc.str_replace('=', '', base64_encode($result)); } } static function randStr($randLength = 6, $addtime = 0, $includenumber = 0) { if ($includenumber) { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQEST123456789'; } else { $chars = 'abcdefghijklmnopqrstuvwxyz'; } $len = strlen($chars); $randStr = ''; for ($i = 0; $i < $randLength; $i++) { $randStr .= $chars[mt_rand(0, $len - 1)]; } $tokenvalue = $randStr; if ($addtime) { $tokenvalue = $randStr . time(); } return $tokenvalue; } }
// 批量加密 function index(){ ini_set('max_execution_time', 0);//秒为单位,自己根据需要定义 set_time_limit(0); // $code = $this->arguments['code']; // $sta = $this->arguments['sta']; // $end = $this->arguments['end']; // var_dump($code,$sta,$end); // echo $res = Movies::_encrypt('123'); // echo $res = Movies::_decrypt($res); $moviePath = FCPATH.'movie'.DIRECTORY_SEPARATOR; // 视频目录 $data = [ ['ID'=>1,'VideoFile'=>'huzongdieying.zip'], ['ID'=>2,'VideoFile'=>'27000084-bstg.mp4'] ]; $obj = new FilmFiles(); foreach($data as $key=>$val){ $filePath = $moviePath.$val['VideoFile']; $res = Movies::movieModify($filePath); if($res){ $where = ['ID'=>$val['ID']]; $info = [ 'EncryptType'=>3, 'SecretKey'=>$res['Pkey'], 'SecretEncrypt'=>$res['passStr'] ]; $sta = $obj->updateLine($where,$info); var_dump($res,$sta); } } } // 批量解密 function indexOut(){ ini_set('max_execution_time', 0);//秒为单位,自己根据需要定义 set_time_limit(0); $moviePath = FCPATH.'movie'.DIRECTORY_SEPARATOR; $data = [ ['ID'=>1,'VideoFile'=>'a.mkv'], ['ID'=>2,'VideoFile'=>'b.mkv'] ]; $obj = new FilmFiles(); $where = ['ID'=>1,'ID'=>2]; $data = $obj->getList(); foreach($data as $val){ $filePath = $moviePath.$val->VideoFile; $res = Movies::movieReduction($filePath, $val->SecretEncrypt, $val->SecretKey); if($res){ $where = ['ID'=>$val->ID]; $info = [ 'EncryptType'=>0, 'SecretKey'=>'', 'SecretEncrypt'=>'' ]; $sta = $obj->updateLine($where,$info); var_dump($res,$sta); } } }
以下是数据库类,可以参考
<?php /* * js * Time 14:26 * File FilmFiles.php * 数据库Model处理数据更改 */ namespace CoreModelPayfilms; use ConfigDatabase; class FilmFiles { //Model Path: CoreModel/Payfilms protected $db; protected $bld; public $Total = 0; public function __construct() { $connect = Database::connect(); $this->db = &$connect; $this->bld = $this->db->table($this->Table); } private $Table = "payfilm_file"; public $SelectFields = "ID,`DoubanID` ,`VideoFile` ,`VideoSize` ,`VideoMD5` ,`TorrentFile` ,`TorrentMD5` ,`FrameType` ,`Ratio` ,`Bitrate` ,`Format` ,`Acoustics` ,`SoundChannel` ,`EncryptType` ,`SecretKey` ,`SecretEncrypt`"; function getCount($where = []) { $this->bld->select("count(ID) as Total"); if (isset($where["limit"])) { unset($where["limit"]); } $this->where($where); $res = $this->bld->get()->getResultArray(); log_message("debug", "CoreModel/Payfilms/FilmFiles ->getCount SQL: " . $this->db->getLastQuery()); return $res[0]["Total"]; } function where($where) { foreach ($where as $k => $v) { switch ($k) { case "ID": $this->bld->where("ID", $v); break; case "DoubanID": $this->bld->where("DoubanID", $v); break; case "VideoFile": $this->bld->where("VideoFile", $v); break; case "VideoSize": $this->bld->where("VideoSize", $v); break; case "VideoMD5": $this->bld->where("VideoMD5", $v); break; case "TorrentFile": $this->bld->where("TorrentFile", $v); break; case "TorrentMD5": $this->bld->where("TorrentMD5", $v); break; case "FrameType": $this->bld->where("FrameType", $v); break; case "Ratio": $this->bld->where("Ratio", $v); break; case "Bitrate": $this->bld->where("Bitrate", $v); break; case "Format": $this->bld->where("Format", $v); break; case "Acoustics": $this->bld->where("Acoustics", $v); break; case "SoundChannel": $this->bld->where("SoundChannel", $v); break; case "EncryptType": $this->bld->where("EncryptType", $v); break; case "SecretKey": $this->bld->where("SecretKey", $v); break; case "SecretEncrypt": $this->bld->where("SecretEncrypt", $v); break; case "operator": foreach ($v as $a => $b) { if (array_key_exists(0, $b)) { $this->bld->where($a . $b[0], $b[1]); continue; } foreach ($b as $n => $m) { $this->bld->where($a . $n, $m); } } break; case "between": foreach ($v as $a => $b) { $this->bld->where($a . ">=", $b[0]); $this->bld->where($a . "<=", $b[1]); } break; case "order_by": foreach ($v as $a => $b) { $this->bld->orderBy($a, $b); } break; case "not_in": foreach ($v as $a => $b) { $this->bld->whereNotIn($a, $b); } break; case "like": foreach ($v as $a => $b) { $this->bld->like($a, $b); } case "limit": $this->bld->limit($v, isset($where["offset"]) ? $where["offset"] : 0); break; } } } function getList($where = []) { $this->bld->select($this->SelectFields); $this->where($where); $this->Total = $this->bld->countAllResults(false); $res = $this->bld->get()->getResult(); log_message("debug", "CoreModel/Payfilms/FilmFiles->getList SQL: " . $this->db->getLastQuery()); if (count($res) > 0) { return $res; } return false; } function updateLine($where, $info) { $this->where($where); $data = []; foreach ($info as $k => $v) { switch ($k) { case "DoubanID": $data["DoubanID"] = $v; break; case "VideoFile": $data["VideoFile"] = $v; break; case "VideoSize": $data["VideoSize"] = $v; break; case "VideoMD5": $data["VideoMD5"] = $v; break; case "TorrentFile": $data["TorrentFile"] = $v; break; case "TorrentMD5": $data["TorrentMD5"] = $v; break; case "FrameType": $data["FrameType"] = $v; break; case "Ratio": $data["Ratio"] = $v; break; case "Bitrate": $data["Bitrate"] = $v; break; case "Format": $data["Format"] = $v; break; case "Acoustics": $data["Acoustics"] = $v; break; case "SoundChannel": $data["SoundChannel"] = $v; break; case "EncryptType": $data["EncryptType"] = $v; break; case "SecretKey": $data["SecretKey"] = $v; break; case "SecretEncrypt": $data["SecretEncrypt"] = $v; break; } } $this->bld->update($data); log_message("debug", "CoreModel/Payfilms/FilmFiles->updateLine SQL: " . $this->db->getLastQuery()); if ($this->db->affectedRows() > 0) { return true; } return false; } function deleteLine($where) { $this->where($where); $this->bld->delete(); log_message("debug", "CoreModel/Payfilms/FilmFiles->deleteLine SQL: " . $this->db->getLastQuery()); if ($this->db->affectedRows() > 0) { return true; } return false; } function insertLine($info) { $data = [ "DoubanID" => $info["DoubanID"], "VideoFile" => $info["VideoFile"], "VideoSize" => $info["VideoSize"], "VideoMD5" => $info["VideoMD5"], "TorrentFile" => $info["TorrentFile"], "TorrentMD5" => $info["TorrentMD5"], "FrameType" => $info["FrameType"], "Ratio" => $info["Ratio"], "Bitrate" => $info["Bitrate"], "Format" => $info["Format"], "Acoustics" => $info["Acoustics"], "SoundChannel" => $info["SoundChannel"], "EncryptType" => $info["EncryptType"], "SecretKey" => $info["SecretKey"], "SecretEncrypt" => $info["SecretEncrypt"], ]; $this->bld->insert($data); log_message("debug", "CoreModel/Payfilms/FilmFiles->insertLine SQL: " . $this->db->getLastQuery()); if ($this->db->affectedRows() > 0) { return $this->db->insertID(); } return false; } function updateByID($ID, $info) { return $this->updateLine(["ID" => $ID], $info); } function getItemByID($ID) { $res = $this->getList(["ID" => $ID]); if (is_array($res)) { return $res[0]; } return false; } function deleteByID($DoubanID) { return $this->deleteLine(["DoubanID" => $DoubanID]); } function getListByDouban($DoubanID, $Ext = []) { $where = ["DoubanID" => $DoubanID]; $where = array_merge($where, $Ext); $res = $this->getList($where); if (is_array($res)) { return $res; } return false; } function deleteByDouban($DoubanID) { return $this->deleteLine(["DoubanID" => $DoubanID]); } }