Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- /**
- Copyright (c) 2011, NullWarez All rights reserved.
- Redistribution and use in source and binary forms, with or without modification,
- are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
- */
- /**
- *
- * @package PHP DC++ Library (Non Threads)
- * @version 1.1.3a
- * @author NullWarez
- * @copyright Copyright (c) 2011, NullWarez
- * @license 3-clause BSD
- *
- */
- class PHPDClib
- {
- private $handle_connection;
- private $options = array(
- 'host' => 'localhost',
- 'port' => '411',
- 'bind_ip' => '0.0.0.0',
- 'nickname' => 'PHPDClib',
- 'password' => '',
- 'description' => 'DC++ Library sf.net/projects/phpdclibrary',
- 'email' => '',
- 'connection' => 'LAN(T1)',
- 'tag' => '<PHPDCLib++ V:1.1.3a,M:P,H:1/0/0,S:10>',
- 'sharesize' => '0',
- 'userlist' => 0,
- 'debug' => 0,
- 'frequency_low' => 300000,
- 'frequency_high' => 1000,
- 'read_buffer_size' => 256000,
- 'func_chat_public' => 'chat_public',
- 'func_chat_private' => 'chat_private',
- 'func_event_handler' => 'event_handler'
- );
- private $control = array(
- 'connected' => false
- );
- public $hub_info = array(
- 'hubname' => '',
- 'userlist' => array()
- );
- private $curent_buffer = null;
- private $read_buffer = null;
- private $read_buffer_array = array();
- private $socket_tcp_recvspace = 0;
- private $frequency = 0;
- /**
- * Main function to connect
- *
- * @access public
- * @param array $optionArray
- */
- public function connect($optionArray)
- {
- $this->options = array_merge($this->options, $optionArray);
- $this->reconnect();
- while(1)
- {
- usleep($this->frequency);
- if($this->sock_error_trigger())
- {
- $this->reconnect();
- continue;
- }
- if($this->read_buffer_array || $this->read_buffer !== null)
- {
- if($this->frequency != $this->options['frequency_high'])
- $this->frequency = $this->options['frequency_high'];
- }
- else
- {
- if($this->frequency != $this->options['frequency_low'])
- $this->frequency = $this->options['frequency_low'];
- }
- if($this->read_socket())
- continue;
- if(!$this->read_buffer_array)
- continue;
- $this->curent_buffer = array_shift($this->read_buffer_array);
- $this->_debug("RX: $this->curent_buffer");
- $temp_cmd = $this->get_cmd();
- do
- {
- if('MyINFO' === $temp_cmd)
- {
- if(!$this->control['connected']) break;
- if(!$this->options['userlist']) break;
- $str_pos = strpos($this->curent_buffer, 'L ');
- $tmp = substr($this->curent_buffer, $str_pos+2);
- $str_pos = strpos($tmp, ' ');
- $tmp = substr($tmp, 0, $str_pos);
- $this->hub_info['userlist'][$tmp] = '';
- }
- else if('$CHAT' === $temp_cmd)
- {
- if(!$this->control['connected']) break;
- $msg_array = $this->get_public_message();
- if($msg_array !== false)
- $this->options['func_chat_public']($msg_array[0], $msg_array[1], $this);
- }
- else if('Hello' === $temp_cmd)
- {
- if($this->control['connected']) break;
- $nickname = substr($this->curent_buffer, strpos($this->curent_buffer, ' ')+1);
- if($nickname != $this->options['nickname'])
- {
- $this->options['func_event_handler']('>BadNick', $this);
- break;
- }
- $this->write_socket('$Version 1,0091');
- $this->write_socket('$MyINFO $ALL '.$this->options['nickname'].' '.$this->options['description'].$this->options['tag'].'$ $'.$this->options['connection'].'1$'.$this->options['email'].'$'.$this->options['sharesize'].'$');
- if($this->options['userlist'])
- $this->write_socket('$GetNickList');
- $this->control['connected'] = true;
- }
- else if('Quit' === $temp_cmd)
- {
- if(!$this->control['connected']) break;
- if(!$this->options['userlist']) break;
- $tmp = substr($this->curent_buffer, 6);
- if(isset($this->hub_info['userlist'][$tmp]))
- unset($this->hub_info['userlist'][$tmp]);
- }
- else if('To:' === $temp_cmd)
- {
- if(!$this->control['connected']) break;
- $msg_array = $this->get_private_message();
- if($msg_array !== false)
- $this->options['func_chat_private']($msg_array[0], $msg_array[1], $this);
- }
- else if('UserCommand' === $temp_cmd)
- {
- break;
- }
- else if('Lock' === $temp_cmd)
- {
- if($this->control['connected']) break;
- preg_match("/Lock (.*) Pk/i", $this->curent_buffer, $lock);
- if($this->options['userlist'])
- $this->write_socket('$Supports NoHello');
- $this->write_socket('$Key '.$this->lock2key($lock[1]));
- $this->write_socket('$ValidateNick '.$this->options['nickname']);
- if(!empty($this->options['password']))
- $this->write_socket('$MyPass '.$this->options['password']);
- }
- else if('HubName' === $temp_cmd)
- {
- if($this->control['connected']) break;
- $this->hub_info['hubname'] = substr($this->curent_buffer, 9);
- }
- else if('GetPass' === $temp_cmd)
- {
- if($this->control['connected']) break;
- $this->options['func_event_handler']('GetPass', $this);
- }
- else if('ForceMove' === $temp_cmd)
- {
- $this->options['func_event_handler']($this->curent_buffer, $this);
- }
- else if('HubIsFull' === $temp_cmd)
- {
- $this->disconnect();
- $this->options['func_event_handler']('$HubIsFull', $this);
- }
- }while(0);
- // Free the memory
- if($this->curent_buffer !== null)
- {
- $this->curent_buffer = null;
- $temp_cmd = null;
- }
- }
- }
- /**
- * Function to send public messages. Can be used in Callback functions
- *
- * @access public
- * @param string $msg
- */
- public function send_public_message($msg)
- {
- $this->write_socket('<'.$this->options['nickname'].'> '.$this->nmdcspecialchars($msg, true));
- }
- /**
- * Function to send private messages. Can be used in Callback functions
- *
- * @access public
- * @param string $to
- * @param string $msg
- */
- public function send_private_message($to, $msg)
- {
- $this->write_socket('$To: '.$to.' From: '. $this->options['nickname'].' $<'.$this->options['nickname'].'> '.$this->nmdcspecialchars($msg, true));
- }
- /**
- * Function of receiving commands, protocol NMDC
- *
- * @access private
- */
- private function get_cmd()
- {
- if($this->curent_buffer[0] === '<')
- return '$CHAT';
- elseif($this->curent_buffer[0] !== '$')
- return false;
- return substr($this->curent_buffer, 1, strpos($this->curent_buffer, ' ')-1);
- }
- /**
- * Function for receiving public messages
- *
- * @access private
- */
- private function get_public_message()
- {
- $str_pos = strpos($this->curent_buffer, '>');
- $msg_array[0] = substr($this->curent_buffer, 1, $str_pos-1);
- if($msg_array[0] === $this->options['nickname'])
- return false;
- $msg_array[1] = $this->nmdcspecialchars(substr($this->curent_buffer, $str_pos+2), false);
- return $msg_array;
- }
- /**
- * Function for receiving private messages
- *
- * @access private
- */
- private function get_private_message()
- {
- $str_pos_first = strpos($this->curent_buffer, '<');
- $str_pos_last = strpos($this->curent_buffer, '>', $str_pos_first);
- $msg_array[0] = substr($this->curent_buffer, $str_pos_first+1, $str_pos_last - $str_pos_first -1);
- if($msg_array[0] === $this->options['nickname'])
- return false;
- $msg_array[1] = $this->nmdcspecialchars(substr($this->curent_buffer, $str_pos_last+2), false);
- return $msg_array;
- }
- /**
- * Function, character by character to read from socket
- *
- * @access private
- */
- private function read_socket()
- {
- while(1)
- {
- $return_data = socket_read($this->handle_connection, $this->socket_tcp_recvspace, PHP_BINARY_READ);
- if($return_data === false)
- {
- return false;
- }
- else if($return_data === '')
- {
- $this->reconnect();
- return true;
- }
- $this->read_buffer .= $return_data;
- unset($return_data);
- $position = strrpos($this->read_buffer, '|');
- if($position === false)
- return false;
- $raw_data = explode('|', substr($this->read_buffer, 0, $position));
- foreach ($raw_data as $val)
- {
- $this->read_buffer_array[] = $val;
- }
- $raw_buffer = substr($this->read_buffer, $position+1);
- unset($position, $raw_data);
- if($raw_buffer === false)
- {
- $this->read_buffer = null;
- return false;
- }
- if(strlen($this->read_buffer) < $this->options['read_buffer_size'])
- {
- $this->read_buffer = $raw_buffer;
- return false;
- }
- $this->_debug('SYS(BUFFER OVERFLOW) - size: '.strlen($this->read_buffer).' max_size: '.$this->options['read_buffer_size']);
- $this->options['func_event_handler']('sysbufoverflow', $this);
- return false;
- }
- }
- /**
- * Function write in socket
- *
- * @access private
- */
- private function write_socket($cmd)
- {
- $this->_debug("TX: $cmd");
- $cmd .='|';
- $len = strlen($cmd);
- $offset = 0;
- while ($offset < $len)
- {
- $sent = socket_write($this->handle_connection, substr($cmd, $offset), $len-$offset);
- if($sent === false) {
- // Error occurred, break the while loop
- break;
- }
- $offset += $sent;
- if($offset < $len)
- $this->_debug('SOCKET_WRITE FRAG: len:'.$len.' writed: '.$offset);
- }
- if ($offset < $len)
- {
- $this->_debug('SOCKET_WRITE ERROR: '.socket_last_error());
- return false;
- }
- return true;
- }
- /**
- * Function for immediate reconnection
- *
- * @access private
- */
- public function reconnect()
- {
- if($this->control['connected'])
- {
- socket_close($this->handle_connection);
- }
- $this->control['connected'] = false;
- $this->hub_info['userlist'] = array();
- $this->curent_buffer = null;
- $this->read_buffer = null;
- $this->read_buffer_array = array();
- $this->handle_connection = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
- socket_bind($this->handle_connection, $this->options['bind_ip']);
- $this->socket_tcp_recvspace = socket_get_option($this->handle_connection, SOL_SOCKET, SO_RCVBUF);
- socket_connect($this->handle_connection, $this->options['host'], $this->options['port']);
- socket_set_nonblock($this->handle_connection);
- if($this->frequency != $this->options['frequency_low'])
- $this->frequency = $this->options['frequency_low'];
- }
- /**
- * Function to disconnect
- *
- * @access public
- */
- public function disconnect()
- {
- $this->write_socket('$Quit');
- $this->control['connected'] = false;
- $this->hub_info['userlist'] = array();
- socket_close($this->handle_connection);
- }
- /**
- * Function to send raw commands
- *
- * @access public
- * @param string $command
- */
- public function send_raw_command($command)
- {
- $this->write_socket($command);
- }
- /**
- * Convert special characters in NMDC protocol
- *
- * @access private
- * @param string $str
- * @param bool $reverse
- */
- private function nmdcspecialchars($str, $reverse)
- {
- if($reverse)
- {
- $search = array('$', '|', '&');
- $replace = array('$', '|', '&');
- return str_replace($search, $replace, $str);
- }
- else
- {
- $search = array('&', '$', '|', '$', '|');
- $replace = array('&amp;', '&#36', '&#124;', '$', '|');
- return str_replace($search, $replace, $str);
- }
- }
- /**
- * Function generation lock2key key to the protocol specification NMDC
- *
- * @access private
- * @param string $_LOCK
- */
- private function lock2key($_LOCK)
- {
- $lockLength = strlen($_LOCK);
- $LockToKey = '';
- for ($j = 0; $j < strlen($_LOCK); $j++)
- {
- if($j == 0) {
- $h = ord($_LOCK{0}) ^ ord( $_LOCK{ $lockLength - 1} ) ^ ord( $_LOCK{ $lockLength - 2} ) ^ 5;
- }
- else {
- $h = ord($_LOCK{$j}) ^ ord($_LOCK{$j-1});
- }
- $h = $h % 256;
- $a = (($h<<4) & 240) | (($h>>4) & 15);
- if($a == '126' or $a == '124' or $a == '96' or $a == '36' or $a == '5' or $a == '0') {
- $LockToKey .= '/%DCN';
- if ($a < 100) $LockToKey .= "0";
- if ($a < 10) $LockToKey .= "0";
- $LockToKey .= $a.'%/';
- }
- else {
- $LockToKey .= chr($a);
- }
- }
- return $LockToKey;
- }
- /**
- * Function debugging, to monitor incoming and outgoing data
- *
- * @access private
- * @param string $str
- */
- private function _debug($str)
- {
- if(!$this->options['debug'])
- return;
- echo $str."\n\n";
- }
- /**
- * Function check error codes.
- *
- * @access private
- */
- private function sock_error_trigger()
- {
- $err_num = socket_last_error($this->handle_connection);
- if($err_num === 0) // *nix, Windows (In non-blocking mode when the connection is not established, but we're trying to read data from socket)
- return false;
- else if($err_num === 35) // *nix (tested on FreeBSD)
- return false;
- else if($err_num === 10035) // Windows (tested on Windows 7)
- return false;
- else
- return true;
- }
- }
- ?>
Advertisement
Add Comment
Please, Sign In to add comment