首页 > 代码库 > php 获取优酷视频的真实地址(2014.6月新算法)

php 获取优酷视频的真实地址(2014.6月新算法)

  上个礼拜发现优酷改版了,各种过滤优酷广告的插件都失效了,于是我百度了一下(谷歌也不能用了)发现优酷改算法了,在ckplayer论坛发现有人在6月25号发了个php 的优酷代理文件,下载下来发现,能用但只能获取mp4格式的视频地址,而且php还加密了,没办法查看源码,后来通过微盾解密发现其中的源码,结合以前自己写的一个优酷视频解析类。。。。

感谢    3shi大大 具体分析请见 3shi大大的文章  优酷视频真实地址解析  (当然现在不能用了,主要看分析

 

ps.  新算法是从别人那里解密出来的所以有可能存在错误,当然也没有注释,不过我试了几个视频都可以解析。

 

下面是源码:

文件名为:youku.class.php

  1 <?php  2   3 class Youku {  4   5     const USER_AGENT = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36";  6     const REFERER = "http://www.youku.com";  7     const FORM_ENCODE = "GBK";  8     const TO_ENCODE = "UTF-8";  9     private static $base = "http://v.youku.com/player/getPlaylist/VideoIDS/"; 10     private static $source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\\:._-1234567890"; 11     private static $sz = ‘-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1‘; 12     private static $str = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/‘; 13  14     public static function parse($url){ 15         preg_match("#id\_([\w=]+)#", $url, $matches); //id里可以有=号 16         if (empty($matches)){ 17             $html = self::_cget($url); 18             preg_match("#videoId2\s*=\s*\‘(\w+)\‘#", $html, $matches); 19             if(!$matches) return false; 20         } 21         //根据you vid 获取相应的视频地址 22         return self::_getYouku(trim($matches[1])); 23     } 24     /** 25      * [_cget curl获取数据] 26      * @param  [type]  $url     [url地址] 27      * @param  boolean $convert [是否转换编码] 28      * @param  integer $timeout [超时时间] 29      * @return [type]           [description] 30      */ 31     public static function _cget($url,$convert=false,$timeout=10){ 32         $ch=curl_init($url); 33         curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); 34         curl_setopt($ch,CURLOPT_TIMEOUT,$timeout); 35         curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout); 36         curl_setopt($ch,CURLOPT_USERAGENT,self::USER_AGENT); 37         curl_setopt($ch,CURLOPT_REFERER,self::REFERER);        38         curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1); //跟随301跳转 39         curl_setopt($ch,CURLOPT_AUTOREFERER,1); //自动设置referer               40         $res=curl_exec($ch); 41         curl_close($ch); 42         if($convert){ 43             $res=mb_convert_encoding($res,self::TO_ENCODE,self::FORM_ENCODE); 44         } 45         return $res; 46     }     47  48     //start 获得优酷视频需要用到的方法 49     private static function getSid(){ 50         $sid = time().(mt_rand(0,9000)+10000); 51         return $sid; 52     } 53  54     private static function getKey($key1,$key2){ 55         $a = hexdec($key1); 56         $b = $a ^0xA55AA5A5; 57         $b = dechex($b); 58         return $key2.$b; 59     } 60  61     private static function getFileid($fileId,$seed){ 62         $mixed = self::getMixString($seed); 63         $ids = explode("*",rtrim($fileId,‘*‘)); //去掉末尾的*号分割为数组 64         $realId = ""; 65         for ($i=0;$i<count($ids);$i++){ 66             $idx = $ids[$i]; 67             $realId .= substr($mixed,$idx,1); 68         }   69         return $realId; 70     }  71  72     private static function getMixString($seed){ 73         $mixed = ""; 74         $source = self::$source; 75         $len = strlen($source); 76         for($i=0;$i<$len;$i++){ 77             $seed = ($seed * 211 + 30031)%65536; 78             $index = ($seed / 65536 * strlen($source)); 79             $c = substr($source,$index,1); 80             $mixed .= $c; 81             $source = str_replace($c,"",$source); 82         } 83         return $mixed; 84     } 85  86     private static function yk_d($a){ 87         if (!$a) { 88             return ‘‘; 89         } 90         $f = strlen($a); 91         $b = 0; 92         $str = self::$str; 93         for ($c = ‘‘; $b < $f;) { 94             $e = self::charCodeAt($a, $b++) & 255; 95             if ($b == $f) { 96                 $c .= self::charAt($str, $e >> 2); 97                 $c .= self::charAt($str, ($e & 3) << 4); 98                 $c .= ‘==‘; 99                 break;100             }101             $g = self::charCodeAt($a, $b++);102             if ($b == $f) {103                 $c .= self::charAt($str, $e >> 2);104                 $c .= self::charAt($str, ($e & 3) << 4 | ($g & 240) >> 4);105                 $c .= self::charAt($str, ($g & 15) << 2);106                 $c .= ‘=‘;107                 break;108             }109             $h = self::charCodeAt($a, $b++);110             $c .= self::charAt($str, $e >> 2);111             $c .= self::charAt($str, ($e & 3) << 4 | ($g & 240) >> 4);112             $c .= self::charAt($str, ($g & 15) << 2 | ($h & 192) >> 6);113             $c .= self::charAt($str, $h & 63);114         }115         return $c;116     }117     private static function yk_na($a){118         if (!$a) {119             return ‘‘;120         }121 122         $h = explode(‘,‘, self::$sz);123         $i = strlen($a);124         $f = 0;125         for ($e = ‘‘; $f < $i;) {126             do {127                 $c = $h[self::charCodeAt($a, $f++) & 255];128             } while ($f < $i && -1 == $c);129             if (-1 == $c) {130                 break;131             }132             do {133                 $b = $h[self::charCodeAt($a, $f++) & 255];134             } while ($f < $i && -1 == $b);135             if (-1 == $b) {136                 break;137             }138             $e .= self::fromCharCode($c << 2 | ($b & 48) >> 4);139             do {140                 $c = self::charCodeAt($a, $f++) & 255;141                 if (61 == $c) {142                     return $e;143                 }144                 $c = $h[$c];145             } while ($f < $i && -1 == $c);146             if (-1 == $c) {147                 break;148             }149             $e .= self::fromCharCode(($b & 15) << 4 | ($c & 60) >> 2);150             do {151                 $b = self::charCodeAt($a, $f++) & 255;152                 if (61 == $b) {153                     return $e;154                 }155                 $b = $h[$b];156             } while ($f < $i && -1 == $b);157             if (-1 == $b) {158                 break;159             }160             $e .= self::fromCharCode(($c & 3) << 6 | $b);161         }162         return $e;163     }164     private static function yk_e($a, $c){165         for ($f = 0, $i, $e = ‘‘, $h = 0; 256 > $h; $h++) {166             $b[$h] = $h;167         }168         for ($h = 0; 256 > $h; $h++) {169             $f = (($f + $b[$h]) + self::charCodeAt($a, $h % strlen($a))) % 256;170             $i = $b[$h];171             $b[$h] = $b[$f];172             $b[$f] = $i;173         }174         for ($q = ($f = ($h = 0)); $q < strlen($c); $q++) {175             $h = ($h + 1) % 256;176             $f = ($f + $b[$h]) % 256;177             $i = $b[$h];178             $b[$h] = $b[$f];179             $b[$f] = $i;180             $e .= self::fromCharCode(self::charCodeAt($c, $q) ^ $b[($b[$h] + $b[$f]) % 256]);181         }182         return $e;183     }184     185     private static function fromCharCode($codes){186         if (is_scalar($codes)) {187             $codes = func_get_args();188         }189         $str = ‘‘;190         foreach ($codes as $code) {191             $str .= chr($code);192         }193         return $str;194     }195     private static function charCodeAt($str, $index){196         static $charCode = array();197         $key = md5($str);198         $index = $index + 1;199         if (isset($charCode[$key])) {200             return $charCode[$key][$index];201         }202         $charCode[$key] = unpack(‘C*‘, $str);203         return $charCode[$key][$index];204     }205 206     private static function charAt($str, $index = 0){207         return substr($str, $index, 1);208     }209 210 211     /**212      * [_getYouku description]213      * @param  [type] $vid [视频id]214      * @return [type]      [description]215      */216     public static function _getYouku($vid){217         //$link = "http://v.youku.com/player/getPlayList/VideoIDS/{$vid}/Pf/4"; //获取视频信息json 有些视频获取不全(土豆网的 火影忍者)218         $blink = self::$base.$vid;219         $link = $blink."/Pf/4/ctype/12/ev/1";220         $retval = self::_cget($link);221         $bretval = self::_cget($blink);222         if ($retval) {223             $rs = json_decode($retval, true);224             $brs = json_decode($bretval, true);225             if(!empty($rs[‘data‘][0][‘error‘])){226                 return false;  //有错误返回false227             }228             $data = array();229             $streamtypes = $rs[‘data‘][0][‘streamtypes‘];  //可以输出的视频清晰度230             $streamfileids = $rs[‘data‘][0][‘streamfileids‘];231             $seed = $rs[‘data‘][0][‘seed‘];232             $segs = $rs[‘data‘][0][‘segs‘];233             $ip = $rs[‘data‘][0][‘ip‘];234             $bsegs =  $brs[‘data‘][0][‘segs‘];235             list($sid, $token) = explode(‘_‘, self::yk_e(‘becaf9be‘, self::yk_na($rs[‘data‘][0][‘ep‘])));236             foreach ($segs as $key=>$val) {237                 if(in_array($key,$streamtypes)){238                     foreach($val as $k=> $v){239                         $no = strtoupper(dechex($v[‘no‘])); //转换为16进制 大写240                         if(strlen($no) == 1){241                             $no ="0".$no;  //no 为每段视频序号242                         }243                         //构建视频地址K值244                         $_k = $v[‘k‘];245                         if ((!$_k || $_k == ‘‘) || $_k == ‘-1‘) {246                             $_k = $bsegs[$key][$k][‘k‘];247                         }248                         $fileId = self::getFileid($streamfileids[$key],$seed);249                         $fileId = substr($fileId,0,8).$no.substr($fileId,10);250                         $ep = urlencode(iconv(‘gbk‘, ‘UTF-8‘, self::yk_d(self::yk_e(‘bf7e5f01‘, ((($sid . ‘_‘) . $fileId) . ‘_‘) . $token))));251                         //判断后缀类型 、获得后缀252                         $typeArray = array("flv"=>"flv","mp4"=>"mp4","hd2"=>"flv","3gphd"=>"mp4","3gp"=>"flv","hd3"=>"flv");253                         //判断视频清晰度  254                         $sharpness = array("flv"=>"normal","flvhd"=>"normal","mp4"=>"high","hd2"=>"super","3gphd"=>"high","3gp"=>"normal","hd3"=>"original"); //清晰度 数组255                         $fileType = $typeArray[$key];256                         $data[$sharpness[$key]][$k] = "http://k.youku.com/player/getFlvPath/sid/".$sid."_00/st/{$fileType}/fileid/".$fileId."?K=".$_k."&hd=1&myp=0&ts=".((((($v[‘seconds‘].‘&ypp=0&ctype=12&ev=1&token=‘).$token).‘&oip=‘).$ip).‘&ep=‘).$ep;;257                     }258                 }259             }260             //返回 图片 标题 链接  时长  视频地址261             $data[‘img‘] = $rs[‘data‘][0][‘logo‘];262             $data[‘title‘] = $rs[‘data‘][0][‘title‘];263             $data[‘seconds‘] = $rs[‘data‘][0][‘seconds‘];264             return $data;265         } else {266             return false;267         }268     }269     //end  获得优酷视频需要用到的方法270 }

引入这个类就可以使用: 输出一个带有各种清晰度的 视频url 的数组。

1 require "youku.class.php";2 $url = "http://v.youku.com/v_show/id_XNzM1NjQ0Mzgw.html";3 $data = Youku::parse($url);4 print_r($data);