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));
23 }
24 /**
25 *
26 * @param$url
27 * @paramboolean $convert [是否转换编码]
28 * @paraminteger $timeout [超时时间]
29 * @return
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;
128 } while ($f < $i && -1 == $c);
129 if (-1 == $c) {
130 break;
131 }
132 do {
133 $b = $h;
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 *
213 * @param $vid [视频id]
214 * @return
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']['error'])){
226 return false;//有错误返回false
227 }
228 $data = array();
229 $streamtypes = $rs['data']['streamtypes'];//可以输出的视频清晰度
230 $streamfileids = $rs['data']['streamfileids'];
231 $seed = $rs['data']['seed'];
232 $segs = $rs['data']['segs'];
233 $ip = $rs['data']['ip'];
234 $bsegs =$brs['data']['segs'];
235 list($sid, $token) = explode('_', self::yk_e('becaf9be', self::yk_na($rs['data']['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']['logo'];
262 $data['title'] = $rs['data']['title'];
263 $data['seconds'] = $rs['data']['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);
页:
[1]