function handshake($socket) { $bytes = socket_recv($socket, $buffer, 2048, 0); $header_list = parse_header($buffer); $accept = $header_list['Sec-WebSocket-Key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; $accept = base64_encode(sha1($accept, true)); $upgrade = array('HTTP/1.1 101 Switching Protocols', 'Upgrade: websocket', 'Connection: Upgrade', "Sec-WebSocket-Accept: {$accept}", "WebSocket-Origin: {$header_list['Origin']}", "WebSocket-Location: ws://{$header_list['Host']}/ws/server.php", "\r\n"); $upgrade = implode("\r\n", $upgrade); socket_write($socket, $upgrade); }
/** * 用户 header * * 1 参数 用户标识符 * * 返回值 false 或 连接类型 **/ function header($data, $accept) { $header = parse_header($data, true); $msg = ''; // 最多 4096 信息 if (strlen($data) >= 4096) { return false; } // 系统本身的 api 条用 if (!empty($header['api'])) { // key = 验证的 time = 验证的 $arr = explode('|', trim($header['api']), 2); if (count($arr) != 2) { return false; } list($time, $key) = $arr; if ($time > time() || $time < time() - 10) { return false; } if (empty($this->key) || strlen($key) != 64) { return false; } if (md5($this->key . $time) . md5($time . $this->key) !== $key) { return false; } $msg .= '200'; if (!socket_write($accept, $msg, strlen($msg))) { return false; } return WEBSOCKET_TYPE_API; } // flash 验证信息 if (trim(implode('', $header)) == '<policy-file-request/>') { $msg .= '<?xml version="1.0"?>'; $msg .= '<cross-domain-policy>'; $msg .= '<allow-access-from domain="' . ($this->domain ? '*.' . $this->domain : '*') . '" to-ports="*"/>'; $msg .= '</cross-domain-policy>'; $msg .= ""; socket_write($accept, $msg, strlen($msg)); return false; } // 超过最大在线 if (WEBSOCKET_ONLINE <= count($this->accept)) { return false; } // 来路 $origin = empty($header['origin']) ? empty($header['websocket-origin']) ? '' : $header['websocket-origin'] : $header['origin']; $parse = parse_url($origin); $scheme = empty($parse['scheme']) || $parse['scheme'] != 'https' ? '' : 's'; $origin = $origin && !empty($parse['host']) ? 'http' . $scheme . '://' . $parse['host'] : ''; // 无效来路 if ($this->domain && !empty($parse['host']) && !preg_match('/(^|\\.)' . preg_quote($this->domain, '/') . '$/i', $parse['host'])) { return false; } // 10+ 版本的 if (!empty($header['sec-websocket-key'])) { $type = WEBSOCKET_TYPE_2; $a = base64_encode(sha1(trim($header['sec-websocket-key']) . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)); $msg .= "HTTP/1.1 101 Switching Protocols\r\n"; $msg .= "Upgrade: websocket\r\n"; $msg .= "Connection: Upgrade\r\n"; if ($origin) { $msg .= "Sec-WebSocket-Origin: {$origin}\r\n"; } $msg .= "Sec-WebSocket-Accept: {$a}\r\n"; $msg .= "\r\n"; if (!socket_write($accept, $msg, strlen($msg))) { return false; } return WEBSOCKET_TYPE_2; } // 10- 版本的 if (!empty($header['sec-websocket-key1']) && !empty($header['sec-websocket-key2']) && !empty($header['html'])) { $key1 = $header['sec-websocket-key1']; $key2 = $header['sec-websocket-key2']; $key3 = $header['html']; if (!preg_match_all('/([\\d]+)/', $key1, $key1_num) || !preg_match_all('/([\\d]+)/', $key2, $key2_num)) { return false; } $key1_num = implode($key1_num[0]); $key2_num = implode($key2_num[0]); if (!preg_match_all('/([ ]+)/', $key1, $key1_spc) || !preg_match_all('/([ ]+)/', $key2, $key2_spc)) { return false; } $key1_spc = strlen(implode($key1_spc[0])); $key2_spc = strlen(implode($key2_spc[0])); $key1_sec = pack("N", $key1_num / $key1_spc); $key2_sec = pack("N", $key2_num / $key2_spc); $msg .= "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"; $msg .= "Upgrade: WebSocket\r\n"; $msg .= "Connection: Upgrade\r\n"; if ($origin) { $msg .= "Sec-WebSocket-Origin: {$origin}\r\n"; } $msg .= "Sec-WebSocket-Location: ws{$scheme}://{$this->host}:{$this->port}{$this->path}\r\n"; $msg .= "\r\n"; $msg .= md5($key1_sec . $key2_sec . $key3, true); if (!socket_write($accept, $msg, strlen($msg))) { return false; } return WEBSOCKET_TYPE_1; } return false; }
function parse_message($rawmessage) { global $attachment_delete_alternative, $attachment_uudecode; // Read the header of the message: $count_rawmessage = count($rawmessage); $message = new messageType(); $rawheader = array(); $i = 0; while ($rawmessage[$i] != "") { $rawheader[] = $rawmessage[$i]; $i++; } // Parse the Header: $message->header = parse_header($rawheader); // Now we know if the message is a mime-multipart message: $content_type = split("/", $message->header->content_type[0]); if ($content_type[0] == "multipart") { $message->header->content_type = array(); // We have multible bodies, so we split the message into its parts $boundary = "--" . $message->header->content_type_boundary; // lets find the first part while ($rawmessage[$i] != $boundary) { $i++; } $i++; $part = array(); while ($i <= $count_rawmessage) { if ($rawmessage[$i] == $boundary || $i == $count_rawmessage - 1 || $rawmessage[$i] == $boundary . '--') { $partmessage = parse_message($part); // merge the content-types of the message with those of the part for ($o = 0; $o < count($partmessage->header->content_type); $o++) { $message->header->content_type[] = $partmessage->header->content_type[$o]; $message->header->content_type_charset[] = $partmessage->header->content_type_charset[$o]; $message->header->content_type_name[] = $partmessage->header->content_type_name[$o]; $message->body[] = $partmessage->body[$o]; } $part = array(); } else { if ($i < $count_rawmessage) { $part[] = $rawmessage[$i]; } } if ($rawmessage[$i] == $boundary . '--') { break; } $i++; } // Is this a multipart/alternative multipart-message? Do we have to // delete all non plain/text parts? if ($attachment_delete_alternative && $content_type[1] == "alternative") { $plaintext = false; for ($o = 0; $o < count($message->header->content_type); $o++) { if ($message->header->content_type[$o] == "text/plain") { $plaintext = true; } // we found at least one text/plain } if ($plaintext) { // now we can delete the other parts for ($o = 0; $o < count($message->header->content_type); $o++) { if ($message->header->content_type[$o] != "text/plain") { unset($message->header->content_type[$o]); unset($message->header->content_type_name[$o]); unset($message->header->content_type_charset[$o]); unset($message->body[$o]); } } } } } else { // No mime-attachments in the message: $body = ""; $uueatt = 0; // as default we have no uuencoded attachments for ($i++; $i < $count_rawmessage; $i++) { // do we have an inlay uuencoded file? if (strtolower(substr($rawmessage[$i], 0, 5)) != "begin" || $attachment_uudecode == false) { $body .= $rawmessage[$i] . "\n"; // yes, it seems, we have! } else { $old_i = $i; $uue_infoline_raw = $rawmessage[$i]; $uue_infoline = explode(" ", $uue_infoline_raw); $uue_data = ""; $i++; while ($rawmessage[$i] != "end") { if (strlen(trim($rawmessage[$i])) > 2) { $uue_data .= $rawmessage[$i] . "\n"; } $i++; } // now write the data in an attachment $uueatt++; $message->body[$uueatt] = uudecode($uue_data); $message->header->content_type_name[$uueatt] = ""; for ($o = 2; $o < count($uue_infoline); $o++) { $message->header->content_type_name[$uueatt] .= $uue_infoline[$o]; } $message->header->content_type[$uueatt] = get_mimetype_by_filename($message->header->content_type_name[$uueatt]); } } if ($message->header->content_type[0] == "text/plain") { $body = trim($body); if ($body == "") { $body = " "; } } $body = decode_body($body, $message->header->content_transfer_encoding); $message->body[0] = $body; } if (!isset($message->header->content_type_charset)) { $message->header->content_type_charset = array("ISO-8859-1"); } if (!isset($message->header->content_type_name)) { $message->header->content_type_name = array("unnamed"); } for ($o = 0; $o < count($message->body); $o++) { if (!isset($message->header->content_type_charset[$o])) { $message->header->content_type_charset[$o] = "ISO-8859-1"; } if (!isset($message->header->content_type_name[$o])) { $message->header->content_type_name[$o] = "unnamed"; } } return $message; }
function fetch_and_store_images(array $img_urls) { $return_arr = array('valid_images' => array(), 'invalid_image_urls' => array()); $valid_status = array(200, 301, 304); $kvdb = new SaeKV(); $kvdb->init(); foreach ($img_urls as $hash_size_name => $img_url) { list($hash, $size, $filename) = explode('#', $hash_size_name); if ($filename !== 'none' && file_exists("saestor://tumblrlikes/{$filename}")) { $img = file_get_contents("saestor://tumblrlikes/{$filename}"); } else { $filename = basename($img_url); $img = @file_get_contents($img_url); $fetch_succeed = in_array(parse_header($http_response_header, 'status'), $valid_status); $img_info = array('date' => date('Y-m-d'), 'size' => $size, 'read_counter' => 1, 'remark' => $fetch_succeed ? '' : 'inaccessible'); $kvdb->set($filename, $img_info); if ($img === false || !$fetch_succeed) { $return_arr['invalid_image_urls'][] = $img_url; continue; } else { file_put_contents("saestor://tumblrlikes/{$filename}", $img); } } $return_arr['valid_images'][$img_url] = $img; } return $return_arr; }
function header($data, $accept, $index = 0) { $header = parse_header($data, true); if (strlen($data) >= 4096) { return false; } if (count($this->accept) > WEBSOCKET_ONLINE) { return false; } $msg = ''; if (trim(implode('', $header)) == '<policy-file-request/>') { $msg .= '<?xml version="1.0"?>'; $msg .= '<cross-domain-policy>'; $msg .= '<allow-access-from domain="' . ($this->domain ? '*.' . $this->domain : '*') . '" to-ports="*"/>'; $msg .= '</cross-domain-policy>'; $msg .= ""; socket_write($accept, $msg, strlen($msg)); return false; } $origin = empty($header['origin']) ? empty($header['websocket-origin']) ? '' : $header['websocket-origin'] : $header['origin']; $parse = parse_url($origin); $scheme = empty($parse['scheme']) || $parse['scheme'] != 'https' ? '' : 's'; $origin = $origin && !empty($parse['host']) ? 'http' . $scheme . '://' . $parse['host'] : ''; if ($this->domain && !empty($parse['host']) && !preg_match('/(^|\\.)' . preg_quote($this->domain, '/') . '$/i', $parse['host'])) { return false; } if (!empty($header['sec-websocket-key'])) { $a = base64_encode(sha1(trim($header['sec-websocket-key']) . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)); $msg .= "HTTP/1.1 101 Switching Protocols\r\n"; $msg .= "Upgrade: websocket\r\n"; $msg .= "Connection: Upgrade\r\n"; if ($origin) { $msg .= "Sec-WebSocket-Origin: {$origin}\r\n"; } $msg .= "Sec-WebSocket-Accept: {$a}\r\n"; $msg .= "\r\n"; if (!socket_write($accept, $msg, strlen($msg))) { return false; } return 2; } if (!empty($header['sec-websocket-key1']) && !empty($header['sec-websocket-key2']) && !empty($header['html'])) { $key1 = $header['sec-websocket-key1']; $key2 = $header['sec-websocket-key2']; $key3 = $header['html']; if (!preg_match_all('/([\\d]+)/', $key1, $key1_num) || !preg_match_all('/([\\d]+)/', $key2, $key2_num)) { return false; } $key1_num = implode($key1_num[0]); $key2_num = implode($key2_num[0]); if (!preg_match_all('/([ ]+)/', $key1, $key1_spc) || !preg_match_all('/([ ]+)/', $key2, $key2_spc)) { return false; } $key1_spc = strlen(implode($key1_spc[0])); $key2_spc = strlen(implode($key2_spc[0])); $key1_sec = pack("N", $key1_num / $key1_spc); $key2_sec = pack("N", $key2_num / $key2_spc); $msg .= "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"; $msg .= "Upgrade: WebSocket\r\n"; $msg .= "Connection: Upgrade\r\n"; if ($origin) { $msg .= "Sec-WebSocket-Origin: {$origin}\r\n"; } $msg .= "Sec-WebSocket-Location: ws{$scheme}://{$this->host}:{$this->port}{$this->path}\r\n"; $msg .= "\r\n"; $msg .= md5($key1_sec . $key2_sec . $key3, true); if (!socket_write($accept, $msg, strlen($msg))) { return false; } return 1; } return false; }
function parse_link($link, $level=0) { global $name, $the_file_name, $the_link, $locationheader, $parsed_link, $link_update; if ($level > 3) return FALSE; if ($link == "***" && $link_update) $link = getLinkPath($link_update); $url_parts = @parse_url( $link ); //filter out localhost and reserved or private IPs if (stripos($url_parts["host"], 'localhost') !== false || stripos($url_parts["host"], 'loopback') !== false || (filter_var($url_parts["host"], FILTER_VALIDATE_IP) !== false && (strpos($url_parts["host"],'127') === 0 || filter_var($url_parts["host"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) ) ) { return array('response' => 'HTTP/1.0 400 Bad Request', 'response_code' => 400); } if (substr($link,0,6) == "ftp://") { // Parsing an FTF-Adress $documentpath = $url_parts["path"]; if (strpos($url_parts["host"],"@")) { $url_parts["pass"] .= "@".substr($url_parts["host"],0,strpos($url_parts["host"],"@")); $url_parts["host"] = substr(strrchr($url_parts["host"],"@"),1); } if (preg_match('/[^a-z0-9_.-]/i',$url_parts['host'])){ // exists umlauts ? $IDN = new idna_convert(); $out = $IDN->encode(utf8_encode($url_parts['host'])); // false by error $url_parts['host'] = ($out)? $out : $url_parts['host']; } $ftp = ftp_connect($url_parts["host"]); if (!$url_parts["user"]) $url_parts["user"] = "******"; if (!$url_parts["pass"]) { $mailclass = new StudipMail(); $url_parts["pass"] = $mailclass->getSenderEmail(); } if (!@ftp_login($ftp,$url_parts["user"],$url_parts["pass"])) { ftp_quit($ftp); return FALSE; } $parsed_link["Content-Length"] = ftp_size($ftp, $documentpath); ftp_quit($ftp); if ($parsed_link["Content-Length"] != "-1") { $parsed_link["HTTP/1.0 200 OK"] = "HTTP/1.0 200 OK"; $parsed_link["response_code"] = 200; } else { $parsed_link = FALSE; } $url_parts["pass"] = preg_replace("!@!","%40",$url_parts["pass"]); $the_link = "ftp://".$url_parts["user"].":".$url_parts["pass"]."@".$url_parts["host"].$documentpath; return $parsed_link; } else { if (!empty( $url_parts["path"])){ $documentpath = $url_parts["path"]; } else { $documentpath = "/"; } if ( !empty( $url_parts["query"] ) ) { $documentpath .= "?" . $url_parts["query"]; } $host = $url_parts["host"]; $port = $url_parts["port"]; $scheme = strtolower($url_parts['scheme']); if (!in_array($scheme , words('http https'))) { return array('response' => 'HTTP/1.0 400 Bad Request', 'response_code' => 400); } if ($scheme == "https") { $ssl = TRUE; if (empty($port)) $port = 443; } else { $ssl = FALSE; } if (empty( $port ) ) $port = "80"; if (preg_match('/[^a-z0-9_.-]/i',$host)){ // exists umlauts ? $IDN = new idna_convert(); $out = $IDN->encode(utf8_encode($host)); // false by error $host = ($out)? $out : $host; $pwtxt = ($url_parts['user'] && $url_parts['pass'])? $url_parts['user'].':'. $url_parts['pass'].'@':''; $the_link = $url_parts['scheme'].'://'.$pwtxt.$host.':'.$port.$documentpath; } $socket = @fsockopen( ($ssl? 'ssl://':'').$host, $port, $errno, $errstr, 10 ); if (!$socket) { return array('response' => 'HTTP/1.0 400 Bad Request', 'response_code' => 400); } else { $urlString = "GET ".$documentpath." HTTP/1.0\r\nHost: $host\r\n"; if ($url_parts["user"] && $url_parts["pass"]) { $pass = $url_parts["pass"]; $user = $url_parts["user"]; $urlString .= "Authorization: Basic ".base64_encode("$user:$pass")."\r\n"; } $urlString .= sprintf("User-Agent: Stud.IP v%s File Crawler\r\n", $GLOBALS['SOFTWARE_VERSION']); $urlString .= "Connection: close\r\n\r\n"; fputs($socket, $urlString); stream_set_timeout($socket, 5); $response = ''; do { $response .= fgets($socket, 128); $info = stream_get_meta_data($socket); } while (!feof($socket) && !$info['timed_out'] && strlen($response) < 1024); fclose($socket); } $parsed_link = parse_header($response); // Anderer Dateiname? $disposition_header = $parsed_link['Content-Disposition'] ?: $parsed_link['content-disposition']; if ($disposition_header) { $header_parts = explode(';', $disposition_header); foreach ($header_parts as $part) { $part = trim($part); list($key, $value) = explode('=', $part, 2); if (strtolower($key) === 'filename') { $the_file_name = trim($value, '"'); } } } else { $the_file_name = basename($url_parts['path']) ?: $the_file_name; } // Weg über einen Locationheader: $location_header = $parsed_link["Location"] ?: $parsed_link["location"]; if (in_array($parsed_link["response_code"], array(300,301,302,303,305,307)) && $location_header) { if (strpos($location_header, 'http') !== 0) { $location_header = $url_parts['scheme'] . '://' . $url_parts['host'] . '/' . $location_header; } $parsed_link = parse_link($location_header, $level + 1); } return $parsed_link; } }