最近为了完成一个监控程序,利用 PHP 写了一个这样的利用飞信发短信的程序。临时用的程序东拼西凑一下,难看不要骂。赫赫~
fetion.php 是调用的方法,其他的文件都应该放置在 fetion.php 所在的下级目录 classes 里面。相关的 class 文件可以从此处下载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | < ?php require_once("classes/class.fetion.php"); /* $phone_num 发信人的电话号码,需要开通了飞信 $password 发信人飞信密码 $dst_phone_num 要发送的目的电话号码,需要在飞信中添加为好友 $msg 要发送的文本内容 */ $fetion = new fetion; $fetion->init($phone_num, $password); $fetion->sip_login(); $fetion->sendSMS_toPhone($dst_phone_num, $msg); $fetion->sip_logout(); unset($fesion); ?> |
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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | < ?php require_once("class.curl.php"); require_once("class.SIPC.php"); class Fetion { var $phone_num; var $fetion_num; var $password; var $domain; var $sipc_proxy; var $ssiapp_signin; var $SIPC; // 初始化 fetion class function init($phone_num = NULL, $password = NULL) { // if (!class_exists("SIPC") || !class_exists("curl")) trigger_error("init() ERROR: class SIPC or curl is not exist.", E_USER_ERROR); if ($phone_num == NULL || $password == NULL) trigger_error("init() ERROR: PHONE_NUM or PASSWORD is NULL.", E_USER_ERROR); $this->phone_num = $phone_num; $this->password = $password; $this->domain = "fetion.com.cn"; // 获取 systemconfig $systemconfig_xml = $this->getsystemconfig(); // 获取查询飞信号的 URL $URL = $this->get_ssiapp_signin($systemconfig_xml); // 获取 sipc 登录端口 $SIPC_PROXY = $this->get_sipc_proxy($systemconfig_xml); $this->SIPC = new SIPC($SIPC_PROXY); // 获取飞信号 $SSIAppSignIn_xml = $this->SSIAppSignIn($URL); $this->fetion_num = $this->get_fetion_num($SSIAppSignIn_xml); } function sip_login() { // 密码为空、socket 为空、socket 为假不对 if ($this->password == NULL) trigger_error("sip_login() ERROR: PASSWORD is NULL.", E_USER_ERROR); // 电话号码和飞信号码为空不对 if ($this->phone_num == NULL && $this->fetion_num == NULL) trigger_error("sip_login() ERROR: PHONE_NUM and FETION_NUM is NULL.", E_USER_ERROR); // 如果电话号码存在,但飞信号码不存在则通过初始化获得飞信号 if ($this->phone_num != NULL && $this->fetion_num == NULL) { $this->init($this->phone_num, $this->password); } // 准备第一步 $login_xml[1] = "<args><device type=\"PC\" version=\"6\" client-version=\"2.3.0230\" /><caps value=\"simple-im;im-session;temp-group\" /><events value=\"contact;permission;system-message\" /><user -info attributes=\"all\" /><presence><basic value=\"400\" desc=\"\" /></presence></args>"; $login_request[1] = sprintf("R %s SIP-C/2.0\r\nF: %s\r\nI: 1\r\nQ: 1 R\r\nL: %s\r\n\r\n", $this->domain, $this->fetion_num, strlen($login_xml[1])); $login[1] = $login_request[1].$login_xml[1]; $server_response = $this->SIPC->request($login[1]); preg_match("/nonce=\"([^\"]{32})\"/i", $server_response, $matches); $this->nonce = $matches[1]; // 准备第二步 $login_xml[2] = "<args><device type=\"PC\" version=\"6\" client-version=\"2.3.0230\" /><caps value=\"simple-im;im-session;temp-group\" /><events value=\"contact;permission;system-message\" /><user -info attributes=\"all\" /><presence><basic value=\"400\" desc=\"\" /></presence></args>"; $login_request[2] = sprintf("R %s SIP-C/2.0\r\nF: %s\r\nI: 1\r\nQ: 2 R\r\nA: Digest response=\"%s\",cnonce=\"%s\"\r\nL: %s\r\n\r\n", $this->domain, $this->fetion_num, $this->get_response(), $this->cnonce, strlen($login_xml[1])); $login[2] = $login_request[2].$login_xml[2]; $server_response = $this->SIPC->request($login[2]); } // 向手机发送短信 function sendSMS_toPhone($phone, $sms_text) { $sms_text = iconv('', 'UTF-8', $sms_text); $sendSMS_request = sprintf("M %s SIP-C/2.0\r\nF: %s\r\nI: 2\r\nQ: 1 M\r\nT: tel:%s\r\nN: SendSMS\r\nL: %s\r\n\r\n", $this->domain, $this->fetion_num, $phone, strlen($sms_text)); $sendSMS_request = $sendSMS_request.$sms_text; $server_response = $this->SIPC->request($sendSMS_request); } // 注销 function sip_logout() { $logout_request = sprintf("R %s SIP-C/2.0\r\nF: %s\r\nI: 1 \r\nQ: 3 R\r\nX: 0\r\n\r\n", $this->domain, $this->fetion_num); $server_response = $this->SIPC->request($logout_request); unset($this->SIPC); } // 计算 reponse private function get_response() { $this->cnonce = strtoupper(md5(rand())); // $this->cnonce = "72AE2CD63D6C4AE1678418BE48230029"; // cnonce,password,domain,fetion_num if ($this->nonce == NULL || $this->cnonce == NULL || $this->fetion_num == NULL || $this->domain == NULL || $this->password == NULL ) trigger_error("get_response() ERROR: class not inited.", E_USER_ERROR); $key = md5("{$this->fetion_num}:{$this->domain}:{$this->password}", true); $h1 = strtoupper(md5("{$key}:{$this->nonce}:{$this->cnonce}")); $h2 = strtoupper(md5("REGISTER:{$this->fetion_num}")); $response = strtoupper(md5("{$h1}:{$this->nonce}:{$h2}")); return $response; } // 访问 http://nav.fetion.com.cn/nav/getsystemconfig.aspx 获得系统配置 private function getsystemconfig() { // 检查是否初始化完毕 if ($this->phone_num == NULL) trigger_error("getsystemconfig() ERROR: class not inited.", E_USER_ERROR); // 准备 POST 的数据 $POST_DATA = sprintf("<config><user mobile-no=\"%s\" /><client type=\"PC\" version=\"2.3.0230\" platform=\"W5.1\" /><servers version=\"0\" /><service -no version=\"12\" /><parameters version=\"15\" /><hints version=\"13\" /><http -applications version=\"14\" /><client -config version=\"17\" /></config>", $this->phone_num); $URL = "https://nav.fetion.com.cn/nav/getsystemconfig.aspx"; $XML = $this->curl_post($URL, $POST_DATA); return $XML; } // 获取查询飞信号码的 URL private function get_ssiapp_signin($XML = NULL) { // 检查参数是否设置齐全 if ($XML == NULL) trigger_error("get_ssiapp_signin() ERROR: XML has not been setted.", E_USER_ERROR); preg_match("/<ssi -app-sign-in>([^< ]*)<\/ssi-app-sign-in>/i", $XML, $matches); if (!isset($matches[1])) { trigger_error("get_ssiapp_signin() ERROR: XML is not valid.", E_USER_ERROR); return FALSE; } $this->ssiapp_signin = $matches[1]; return $matches[1]; } // 获得 SIPC 的登录地址和端口 private function get_sipc_proxy($XML = NULL) { // 检查参数是否设置齐全 if ($XML == NULL) trigger_error("get_sipc_proxy() ERROR: XML has not been setted.", E_USER_ERROR); preg_match("/<sipc -proxy>([^< ]*)<\/sipc-proxy>/i", $XML, $matches); if (!isset($matches[1])) { trigger_error("get_sipc_proxy() ERROR: XML is not valid.", E_USER_ERROR); return FALSE; } $this->sipc_proxy = $matches[1]; return $matches[1]; } // 登录取得飞信号码 private function SSIAppSignIn($URL = NULL) { // 检查参数是否设置齐全 if ($URL == NULL || $URL == FALSE) trigger_error("SSIAppSignIn() ERROR: URL has not been setted.", E_USER_ERROR); // 准备 POST 的数据 $POST_DATA = sprintf("mobileno=%s&pwd=%s", $this->phone_num, $this->password); $XML = $this->curl_post($URL, $POST_DATA); return $XML; } private function get_fetion_num($XML = NULL) { // 检查参数是否设置齐全 if ($XML == NULL) trigger_error("get_ssiapp_signin() ERROR: XML has not been setted.", E_USER_ERROR); preg_match("/<user uri=\"sip:([0-9]+)@fetion.com.cn;p=[0-9]+\"/i", $XML, $matches); if (!isset($matches[1])) { trigger_error("get_ssiapp_signin() ERROR: XML is not valid.", E_USER_ERROR); return FALSE; } return $matches[1]; } // 调用 CURL 通过 POST 方法获取信息 private function curl_post($URL = NULL, $POST_DATA = NULL) { // 检查参数是否设置齐全 if ($URL == NULL || $POST_DATA == NULL) trigger_error("curl_post() ERROR: URL or POST_DATA has not been setted.", E_USER_ERROR); $URL = new curl($URL); // 设置 curl 参数 $URL->setopt(CURLOPT_FOLLOWLOCATION, TRUE); $URL->setopt(CURLOPT_SSL_VERIFYPEER, FALSE); $URL->setopt(CURLOPT_SSL_VERIFYHOST, FALSE); // 使用 POST 方法 $URL->setopt(CURLOPT_POST, TRUE); $URL->setopt(CURLOPT_POSTFIELDS, $POST_DATA); // 设置客户端类型 $URL->setopt(CURLOPT_USERAGENT, "User-Agent: IIC2.0/PC 2.3.0230"); $curl_result = $URL->exec(); if ($theError = $URL->hasError()) echo $theError; $URL->close(); return $curl_result; } } ?></user></sipc></ssi> |
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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | < ?php class SIPC { var $_ip; var $_port; var $_request; var $_response; var $_socket; function SIPC($SIPC_addr = NULL) { if (!function_exists("socket_create")) trigger_error("PHP was not built with --with-socket, rebuild PHP to use the socket class.", E_USER_ERROR); if ($SIPC_addr == NULL) trigger_error("SIPC() ERROR: SIPC_addr is not set.", E_USER_ERROR); $addr = explode(":", $SIPC_addr); $this->_ip = $addr[0]; $this->_port = $addr[1]; $this->socket_init(); } // 发送 SIP-C 请求 function request($sip_request = NULL) { if ($sip_request == NULL) trigger_error("socket_write() ERROR: SIPC_REQUEST is not set.", E_USER_ERROR); $this->socket_write($sip_request); $sip_response = $this->socket_read($this->_socket); var_dump($sip_request, $sip_response); return $sip_response; } // 初始化 socket 为 SIP-C 请求准备环境 private function socket_init() { // IP 或 PORT 未设置则退出 if ($this->_ip == NULL || $this->_port == NULL) trigger_error("socket_init() ERROR: IP or PORT is not set.", E_USER_ERROR); // 连接指定的 IP 和 端口 $this->_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_connect($this->_socket, $this->_ip, $this->_port); return $this->_socket; } // 往套接字写数据 private function socket_write($data = NULL) { // 无法写套接字 if ($data == NULL) trigger_error("socket_write() ERROR: DATA is not set.", E_USER_ERROR); socket_write($this->_socket, $data, strlen($data)); } // 从套接字读数据 private function socket_read() { do { $socket_content = $socket_content . socket_read($this->_socket, 4, PHP_BINARY_READ); } while ((bool) strpos($socket_content, "\r\n\r\n") === FALSE); preg_match("/L: ([0-9]+)/i", $socket_content, $matches); if (is_array($matches) && isset($matches[1])) { $length = $matches[1]; $socket_content = $socket_content . socket_read($this->_socket, $length, PHP_BINARY_READ); } return $socket_content; } } ?> |
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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | < ?php /** * @author Dick Munroe (munroe@csworks.com) * @copyright copyright @ 2004-2007, Dick Munroe, released under the GPL. * @license http://www.csworks.com/publications/ModifiedNetBSD.html * @version 1.2.0 * @package cURL * * The cURL class is a thin wrapper around the procedural interface * to cURL provided by PHP. I use it mostly as a base class for * web services whose low level interface is, literally, web pages. * * There are a few differences (value added, I guess) between the interface * provided by this class and the procedural cURL interface. Most * noticable are: * * 1. The curl::exec function (when returning data to the caller rather * than simply outputing it) always parses the HTTP header and returns * only the body portion of the reqeust. The header is available via * the curl::getHeader method. * 2. The status of the last curl::exec is always maintained. It is * available via the curl::getStatus method. In addition to the information * returned by curl_getinfo, that of curl_error and curl_errno is folded * in as well. * * @example ./example.class.curl.php */ // // Edit History: // // Dick Munroe munroe@csworks.com 30-Nov-2004 // Initial Version Created. // // Dick Munroe munroe@csworks.com 01-Dec-2004 // Forgot to check for cURL actually being in this instance of PHP. // // Dick Munroe (munroe@csworks.com) 07-Apr-2006 // Fix tab characters. // Add utility function to return post string. // // Richard W. Schlatter (richard@rth10260.info) 27-Apr-2006 // Extend processing for headers when CURLOPT_FOLLOWLOCATION is also set. // Only the headers of the final page will be used to return parsed headers. // Add utility function to return array of all collected headers. // // Dick Munroe (munroe@csworks.com) 01-May-2006 // asPostString doesn't need to be an object specific method. // // Dick Munroe (munroe@csworks.com) 02-May-2006 // Not all versions of PHP allow returning of a reference to the result // of a function. // // Richard W. Schlatter (richard@rth10260.info) 03-May-2006 // For consistency, return an empty array if there aren't any headers // to be parsed. // // Richard W. Schlatter (richard@rth10260.info) 05-Jun-2006 // Don't parse headers in the event of an error when executing a cURL request. // // Dick Munroe (munroe@csworks.com) 17-Dec-2007 1.2.0 // Add a function to parse post strings as this is frequently needed capability. class curl { /** * The mapping to caseless header names. * * @access private * @var array */ var $m_caseless ; /** * The handle for the current curl session. * * @access private * @var resource */ var $m_handle ; /** * The parsed contents of the HTTP header if one happened in the * message. All repeated elements appear as arrays. * * The headers are stored as an associative array, the key of which * is the name of the header, e.g., Set-Cookie, and the values of which * are the bodies of the header in the order in which they occurred. * * Some headers can be repeated in a single header, e.g., Set-Cookie and * pragma, so each type of header has an array containing one or more * headers of the same type. * * The names of the headers can, potentially, vary in spelling from * server to server and client to client. No attempt to regulate this * is made, i.e., the curl class does not force all headers to lower * or upper class, but it DOES collect all headers of the same type * under the spelling of the type of header used by the FIRST header * of that type. * * For example, two headers: * * 1. Set-Cookie: ... * 2. set-cookie: ... * * Would appear as $this->m_header['Set-Cookie'][0] and ...[1] * * @access private * @var mixed */ var $m_header ; /** * Current setting of the curl options. * * @access private * @var mixed */ var $m_options ; /** * Status information for the last executed http request. Includes the errno and error * in addition to the information returned by curl_getinfo. * * The keys defined are those returned by curl_getinfo with two additional * ones specified, 'error' which is the value of curl_error and 'errno' which * is the value of curl_errno. * * @link http://www.php.net/curl_getinfo * @link http://www.php.net/curl_errno * @link http://www.php.net/curl_error * @access private * @var mixed */ var $m_status ; /** * Collection of headers when curl follows redirections as per CURLOPTION_FOLLOWLOCATION. * The collection includes the headers of the final page too. * * @access private * @var array */ var $m_followed ; /** * curl class constructor * * Initializes the curl class for it's default behavior: * o no HTTP headers. * o return the transfer as a string. * o URL to access. * By default, the curl class will simply read the URL provided * in the constructor. * * @link http://www.php.net/curl_init * @param string $theURL [optional] the URL to be accessed by this instance of the class. */ function curl($theURL=null) { if (!function_exists('curl_init')) { trigger_error('PHP was not built with --with-curl, rebuild PHP to use the curl class.', E_USER_ERROR) ; } $this->m_handle = curl_init() ; $this->m_caseless = null ; $this->m_header = null ; $this->m_options = null ; $this->m_status = null ; $this->m_followed = null ; if (!empty($theURL)) { $this->setopt(CURLOPT_URL, $theURL) ; } $this->setopt(CURLOPT_HEADER, false) ; $this->setopt(CURLOPT_RETURNTRANSFER, true) ; } /** * Free the resources associated with the curl session. * * @link http://www.php.net/curl_close */ function close() { curl_close($this->m_handle) ; $this->m_handle = null ; } /** * Execute the curl request and return the result. * * @link http://www.php.net/curl_exec * @link http://www.php.net/curl_getinfo * @link http://www.php.net/curl_errno * @link http://www.php.net/curl_error * @return string The contents of the page (or other interaction as defined by the * settings of the various curl options). */ function exec() { $theReturnValue = curl_exec($this->m_handle) ; $this->m_status = curl_getinfo($this->m_handle) ; $this->m_status['errno'] = curl_errno($this->m_handle) ; $this->m_status['error'] = curl_error($this->m_handle) ; // // Collect headers espesically if CURLOPT_FOLLOWLOCATION set. // Parse out the http header (from last one if any). // $this->m_header = null ; // // If there has been a curl error, just return a null string. // if ($this->m_status['errno']) { return '' ; } if ($this->getOption(CURLOPT_HEADER)) { $this->m_followed = array() ; $rv = $theReturnValue ; while (count($this->m_followed) < = $this->m_status['redirect_count']) { $theArray = preg_split("/(\r\n){2,2}/", $rv, 2) ; $this->m_followed[] = $theArray[0] ; $rv = $theArray[1] ; } $this->parseHeader($theArray[0]) ; return $theArray[1] ; } else { return $theReturnValue ; } } /** * Returns the parsed http header. * * @param string $theHeader [optional] the name of the header to be returned. * The name of the header is case insensitive. If * the header name is omitted the parsed header is * returned. If the requested header doesn't exist * false is returned. * @returns mixed */ function getHeader($theHeader=null) { // // There can't be any headers to check if there weren't any headers // returned (happens in the event of errors). // if (empty($this->m_header)) { return false ; } if (empty($theHeader)) { return $this->m_header ; } else { $theHeader = strtoupper($theHeader) ; if (isset($this->m_caseless[$theHeader])) { return $this->m_header[$this->m_caseless[$theHeader]] ; } else { return false ; } } } /** * Returns the current setting of the request option. If no * option has been set, it return null. * * @param integer the requested CURLOPT. * @returns mixed */ function getOption($theOption) { if (isset($this->m_options[$theOption])) { return $this->m_options[$theOption] ; } return null ; } /** * Did the last curl exec operation have an error? * * @return mixed The error message associated with the error if an error * occurred, false otherwise. */ function hasError() { if (isset($this->m_status['error'])) { return (empty($this->m_status['error']) ? false : $this->m_status['error']) ; } else { return false ; } } /** * Parse an HTTP header. * * As a side effect it stores the parsed header in the * m_header instance variable. The header is stored as * an associative array and the case of the headers * as provided by the server is preserved and all * repeated headers (pragma, set-cookie, etc) are grouped * with the first spelling for that header * that is seen. * * All headers are stored as if they COULD be repeated, so * the headers are really stored as an array of arrays. * * @param string $theHeader The HTTP data header. */ function parseHeader($theHeader) { $this->m_caseless = array() ; $theArray = preg_split("/(\r\n)+/", $theHeader) ; // // Ditch the HTTP status line. // if (preg_match('/^HTTP/', $theArray[0])) { $theArray = array_slice($theArray, 1) ; } foreach ($theArray as $theHeaderString) { $theHeaderStringArray = preg_split("/\s*:\s*/", $theHeaderString, 2) ; $theCaselessTag = strtoupper($theHeaderStringArray[0]) ; if (!isset($this->m_caseless[$theCaselessTag])) { $this->m_caseless[$theCaselessTag] = $theHeaderStringArray[0] ; } $this->m_header[$this->m_caseless[$theCaselessTag]][] = $theHeaderStringArray[1] ; } } /** * Return the status information of the last curl request. * * @param string $theField [optional] the particular portion * of the status information desired. * If omitted the array of status * information is returned. If a non-existant * status field is requested, false is returned. * @returns mixed */ function getStatus($theField=null) { if (empty($theField)) { return $this->m_status ; } else { if (isset($this->m_status[$theField])) { return $this->m_status[$theField] ; } else { return false ; } } } /** * Set a curl option. * * @link http://www.php.net/curl_setopt * @param mixed $theOption One of the valid CURLOPT defines. * @param mixed $theValue the value of the curl option. */ function setopt($theOption, $theValue) { curl_setopt($this->m_handle, $theOption, $theValue) ; $this->m_options[$theOption] = $theValue ; } /** * @desc Post string as an array * @param string by reference data to be written. * @return array hash containing the post string as individual elements, urldecoded. * @access public */ function &fromPostString(&$thePostString) { $return = array() ; $fields = explode('&', $thePostString) ; foreach($fields as $aField) { $xxx = explode('=', $aField) ; $return[$xxx[0]] = urldecode($xxx[1]) ; } return $return ; } /** * Arrays are walked through using the key as a the name. Arrays * of Arrays are emitted as repeated fields consistent with such things * as checkboxes. * * @desc Return data as a post string. * @param mixed by reference data to be written. * @param string [optional] name of the datum. * @access public */ function &asPostString(&$theData, $theName = NULL) { $thePostString = '' ; $thePrefix = $theName ; if (is_array($theData)) { foreach ($theData as $theKey => $theValue) { if ($thePrefix === NULL) { $thePostString .= '&' . curl::asPostString($theValue, $theKey) ; } else { $thePostString .= '&' . curl::asPostString($theValue, $thePrefix . '[' . $theKey . ']') ; } } } else { $thePostString .= '&' . urlencode((string)$thePrefix) . '=' . urlencode($theData) ; } $xxx =& substr($thePostString, 1) ; return $xxx ; } /** * Returns the followed headers lines, including the header of the retrieved page. * Assumed preconditions: CURLOPT_HEADER and expected CURLOPT_FOLLOWLOCATION set. * The content is returned as an array of headers of arrays of header lines. * * @param none. * @returns mixed an empty array implies no headers. * @access public */ function getFollowedHeaders() { $theHeaders = array() ; if ($this->m_followed) { foreach ( $this->m_followed as $aHeader ) { $theHeaders[] = explode( "\r\n", $aHeader ) ; } ; return $theHeaders ; } return $theHeaders ; } } ?> |
wahaha
/ 2008/08/01http://openfetion.sourceforge.net/
你这个程序用的是fetion 2006的登陆协议,openfetion用的fetion 2008的登陆协议。不过openfetion留了两个暗桩,FETION_URL不对,fetion_http_send_sms函数构建sip的T不对。
你这个也不错,只是不知道中国移动什么时候不兼容2006的登陆协议。
sbilly Reply:
at 08:25:47
八月 1st, 2008
搜索的看到你的 OpenFetion 项目了 :)发现你用的是 2008 的登录协议,无奈我登录的这一一部分已经写完了,暂时懒得改。哈哈这两天看看能不能把登录这一部分改成 2008 的协议。到时候就借鉴你的代码啦~ 哈哈哈哈
sbilly Reply:
at 08:28:39
八月 1st, 2008
另外,我没用HTTP://221.130.45.203/ht/sd.aspx 去登录飞信,直接使用的是 221.130.45.203:8080 所以会有些差别 赫赫
可能你处理的情况时 SIPC over HTTP 吧?
sbilly
/ 2008/08/04奥运版的 Feition 又把登录协议给改了 ……
SIP-C/2.0 401 Unauthorized I: 1 Q: 1 R W: Digest algorithm="MD5-sess;SHA1-sess",nonce="xxxx" R fetion.com.cn SIP-C/2.0 F: xxxx I: 1 Q: 2 R A: Digest algorithm="SHA1-sess",response="xxxx",cnonce="xxxx",salt="xxxx",ssic="xxxx" L: 282 <args><device type="PC" version="36" client-version="3.3.0370" /><caps value="simple-im;im-session;temp-group;personal-group" /><events value="contact;permission;system-message;personal-group" /><user -info attributes="all" /><presence><basic value="400" desc="" /></presence></args>7j
/ 2008/08/06看到sbilly写的代码,我对学习PHP失去了信心,因为我知道我想到达你这个水平太难了。一个PHP的DES加密我都写不来。。为什么人与人的差距这么大呢
sbilly Reply:
at 13:38:46
八月 6th, 2008
吓了我一跳~这代码已经很乱了 我都不好意思拿出来 …… :S
不过没人一开始就会 还不是不断使用慢慢学来的 说到编程我就惭愧呢~
cocobear
/ 2008/11/20lz那个代码点一下出来是主题自带的吗?
有没有代码能让俺瞧瞧,俺也想用。
$socket_content = $socket_content . socket_read($this->_socket, 4, PHP_BINARY_READ);
这行怎么是这样写呢?
socket_content还没有被初始化。
sbilly Reply:
at 16:07:47
十一月 20th, 2008
那是个插件~
官方页面在这里 http://deuced.net/collapsible-elements/32970/
sbilly Reply:
at 16:11:47
十一月 20th, 2008
$this->_socket 在 init 过程中就已经初始化过了~
当然,代码比较脏这是肯定的 :P 自己写着玩的
cocobear
/ 2008/11/21irrecognizable characters !!
似乎不能用这种方式发送短信:
T: tel:136
sbilly Reply:
at 09:22:27
十一月 21st, 2008
这个代码已经不能直接使用了,飞信的协议有过变化
我暂时没有精力去更新代码了~
ssl
/ 2009/01/02楼主,出现以下错误,帮忙看看。
string(110) “M fetion.com.cn SIP-C/2.0 F: 111111 I: 2 Q: 1 M T: tel:111111 N: SendSMS L: 14 hello” string(133) “SIP-C/2.0 403 Forbidden T: tel:15110113807 I: 2 Q: 1 M D: Fri, 02 Jan 2009 12:07:07 GMT XI: 2a603df7229942a4965efe3667e61890 ”
string(64) “R fetion.com.cn SIP-C/2.0 F: 111111 I: 1 Q: 3 R X: 0 ” string(40) “SIP-C/2.0 200 OK I: 1 Q: 3 R X: 0 ”
sbilly
/ 2009/01/02@ssl,
飞信的协议已经有调整了,请自己维护修改这个代码
snow
/ 2009/02/26很好很强大
不过代码如果能改善点更好了
本人愚见 :
有些方法没return 导致无法判断是否成功执行
还有可以加点异常处理的语句 使程序更健壮
sbilly
/ 2009/02/26@snow, 个人闲暇的小玩意,觉得有用自己拿去改着玩吧~
C.Young
/ 2009/03/09openfetion应该是好用的吧,不过确实有bug,刚改了
http://sites.google.com/site/xicabin/openfetion
sbilly
/ 2009/03/10我测试的时候不能直接用,因为写了自己的代码了,所以就没研究它的代码哪里有 bug 了
Zilli
/ 2009/04/22楼上的名字很个性。
Zilli
/ 2009/04/22openfetion是可以使用的。
但是有个问题,新协议接口如果开通了飞信,则不会显示手机号,
如果只是定向的发送到一个手机,那可以把那个手机对应的sid记住;
但是如果通用的,一个手机给随便一个飞信好友的手机号码发送短信,现在就没办法了。
谁有经历再研究一下,如何通过sid获取用户详细信息以得到手机号码,或者最简单的有手机号码就能得到sid。
sbilly
/ 2009/04/22@Zilli, fetion 协议很公开的,可以自己研究一下~