├── .gitignore ├── LICENSE.md ├── README.md ├── TeamSpeak3 ├── Adapter │ ├── AbstractAdapter.php │ ├── Blacklist.php │ ├── FileTransfer.php │ ├── ServerQuery.php │ ├── ServerQuery │ │ ├── Event.php │ │ └── Reply.php │ ├── TSDNS.php │ └── Update.php ├── Helper │ ├── Char.php │ ├── Convert.php │ ├── Crypt.php │ ├── Profiler.php │ ├── Profiler │ │ └── Timer.php │ ├── Signal.php │ ├── Signal │ │ ├── Handler.php │ │ └── ISignal.php │ ├── StringHelper.php │ └── Uri.php ├── Node │ ├── AbstractNode.php │ ├── Channel.php │ ├── Channelgroup.php │ ├── Client.php │ ├── Host.php │ ├── Server.php │ └── Servergroup.php ├── TeamSpeak3.php ├── Transport │ ├── AbstractTransport.php │ ├── TCP.php │ └── UDP.php ├── Ts3Exception.php └── Viewer │ ├── Html.php │ ├── IViewer.php │ └── Text.php └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | Clone of [TS3 PHP Framework 1.1.23](https://www.planetteamspeak.com/) providing the library as composer project including namespaces and follow the PSR-4 Standard. 5 | 6 | 7 | Usage 8 | ===== 9 | 10 | Install via composer: 11 | 12 | "require": { 13 | "fkubis/teamspeak-php-framework": "dev-master" 14 | }, 15 | 16 | Skipp the required_once part of official documentation and replace it with use TeamSpeak3\TeamSpeak3 statement. 17 | 18 | Examples: 19 | 20 | ```php 21 | namespace Foo; 22 | use TeamSpeak3\TeamSpeak3; 23 | 24 | class TeamSpeak3Adapater 25 | { 26 | private $ts3; 27 | public __construct() 28 | { 29 | $this->ts3 = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); 30 | } 31 | 32 | public writeMessage($message) 33 | { 34 | $this->ts3->message($message); 35 | } 36 | } 37 | ``` 38 | 39 | 40 | For more information visit the [official documentation](https://docs.planetteamspeak.com/ts3/php/framework/). 41 | -------------------------------------------------------------------------------- /TeamSpeak3/Adapter/AbstractAdapter.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Adapter; 29 | 30 | use TeamSpeak3\Ts3Exception; 31 | use TeamSpeak3\Transport\TCP; 32 | use TeamSpeak3\Transport\UDP; 33 | use TeamSpeak3\Transport\AbstractTransport; 34 | use TeamSpeak3\Helper\Profiler; 35 | use TeamSpeak3\Helper\Profiler\Timer; 36 | 37 | /** 38 | * @class AbstractAdapter 39 | * @brief Provides low-level methods for concrete adapters to communicate with a TeamSpeak 3 Server. 40 | */ 41 | abstract class AbstractAdapter 42 | { 43 | /** 44 | * Stores user-provided options. 45 | * 46 | * @var array 47 | */ 48 | protected $options = null; 49 | 50 | /** 51 | * Stores an AbstractTransport object. 52 | * 53 | * @var AbstractTransport 54 | */ 55 | protected $transport = null; 56 | 57 | /** 58 | * The AbstractAdapter constructor. 59 | * 60 | * @param array $options 61 | * @return AbstractAdapter 62 | */ 63 | public function __construct(array $options) 64 | { 65 | $this->options = $options; 66 | 67 | if ($this->transport === null) { 68 | $this->syn(); 69 | } 70 | } 71 | 72 | /** 73 | * The AbstractAdapter destructor. 74 | * 75 | * @return void 76 | */ 77 | abstract public function __destruct(); 78 | 79 | /** 80 | * Connects the AbstractTransport object and performs initial actions on the remote 81 | * server. 82 | * 83 | * @throws Ts3Exception 84 | * @return void 85 | */ 86 | abstract protected function syn(); 87 | 88 | /** 89 | * Commit pending data. 90 | * 91 | * @return array 92 | */ 93 | public function __sleep() 94 | { 95 | return array("options"); 96 | } 97 | 98 | /** 99 | * Reconnects to the remote server. 100 | * 101 | * @return void 102 | */ 103 | public function __wakeup() 104 | { 105 | $this->syn(); 106 | } 107 | 108 | /** 109 | * Returns the profiler timer used for this connection adapter. 110 | * 111 | * @return Timer 112 | */ 113 | public function getProfiler() 114 | { 115 | return Profiler::get(spl_object_hash($this)); 116 | } 117 | 118 | /** 119 | * Returns the transport object used for this connection adapter. 120 | * 121 | * @return AbstractTransport 122 | */ 123 | public function getTransport() 124 | { 125 | return $this->transport; 126 | } 127 | 128 | /** 129 | * Loads the transport object object used for the connection adapter and passes a given set 130 | * of options. 131 | * 132 | * @param array $options 133 | * @param string $transport 134 | * @throws Ts3Exception 135 | * @return void 136 | */ 137 | protected function initTransport($options, $transport = "TCP") 138 | { 139 | if (!is_array($options)) { 140 | throw new Ts3Exception("transport parameters must provided in an array"); 141 | } 142 | if($transport == "TCP") 143 | $this->transport = new TCP($options); 144 | else 145 | $this->transport = new UDP($options); 146 | } 147 | 148 | /** 149 | * Returns the hostname or IPv4 address the underlying AbstractTransport object 150 | * is connected to. 151 | * 152 | * @return string 153 | */ 154 | public function getTransportHost() 155 | { 156 | return $this->getTransport()->getConfig("host", "0.0.0.0"); 157 | } 158 | 159 | /** 160 | * Returns the port number of the server the underlying AbstractTransport object 161 | * is connected to. 162 | * 163 | * @return string 164 | */ 165 | public function getTransportPort() 166 | { 167 | return $this->getTransport()->getConfig("port", "0"); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /TeamSpeak3/Adapter/Blacklist.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Adapter; 29 | 30 | use TeamSpeak3\Helper\Profiler; 31 | use TeamSpeak3\Helper\Signal; 32 | use TeamSpeak3\Transport\AbstractTransport; 33 | use TeamSpeak3\Ts3Exception; 34 | 35 | 36 | /** 37 | * @class Blacklist 38 | * @brief Provides methods to check if an IP address is currently blacklisted. 39 | */ 40 | class Blacklist extends AbstractAdapter 41 | { 42 | /** 43 | * The IPv4 address or FQDN of the TeamSpeak Systems update server. 44 | * 45 | * @var string 46 | */ 47 | protected $default_host = "blacklist.teamspeak.com"; 48 | 49 | /** 50 | * The UDP port number of the TeamSpeak Systems update server. 51 | * 52 | * @var integer 53 | */ 54 | protected $default_port = 17385; 55 | 56 | /** 57 | * Stores an array containing the latest build numbers. 58 | * 59 | * @var array 60 | */ 61 | protected $build_numbers = null; 62 | 63 | /** 64 | * Connects the AbstractTransport object and performs initial actions on the remote 65 | * server. 66 | * 67 | * @return void 68 | */ 69 | public function syn() 70 | { 71 | if (!isset($this->options["host"]) || empty($this->options["host"])) { 72 | $this->options["host"] = $this->default_host; 73 | } 74 | if (!isset($this->options["port"]) || empty($this->options["port"])) { 75 | $this->options["port"] = $this->default_port; 76 | } 77 | 78 | $this->initTransport($this->options, "UDP"); 79 | $this->transport->setAdapter($this); 80 | 81 | Profiler::init(spl_object_hash($this)); 82 | 83 | Signal::getInstance()->emit("blacklistConnected", $this); 84 | } 85 | 86 | /** 87 | * The Blacklist destructor. 88 | * 89 | * @return void 90 | */ 91 | public function __destruct() 92 | { 93 | if ($this->getTransport() instanceof AbstractTransport && $this->getTransport()->isConnected()) { 94 | $this->getTransport()->disconnect(); 95 | } 96 | } 97 | 98 | /** 99 | * Returns TRUE if a specified $host IP address is currently blacklisted. 100 | * 101 | * @param string $host 102 | * @throws Ts3Exception 103 | * @return boolean 104 | */ 105 | public function isBlacklisted($host) 106 | { 107 | if (ip2long($host) === false) { 108 | $addr = gethostbyname($host); 109 | 110 | if ($addr == $host) { 111 | throw new Ts3Exception("unable to resolve IPv4 address (" . $host . ")"); 112 | } 113 | 114 | $host = $addr; 115 | } 116 | 117 | $this->getTransport()->send("ip4:" . $host); 118 | $repl = $this->getTransport()->read(1); 119 | $this->getTransport()->disconnect(); 120 | 121 | if (!count($repl)) { 122 | return false; 123 | } 124 | 125 | return ($repl->toInt()) ? false : true; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /TeamSpeak3/Adapter/FileTransfer.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Adapter; 29 | 30 | use TeamSpeak3\Helper\Profiler; 31 | use TeamSpeak3\Helper\Signal; 32 | use TeamSpeak3\Transport\AbstractTransport; 33 | use TeamSpeak3\Ts3Exception; 34 | use TeamSpeak3\Helper\StringHelper; 35 | 36 | /** 37 | * @class FileTransfer 38 | * @brief Provides low-level methods for file transfer communication with a TeamSpeak 3 Server. 39 | */ 40 | class FileTransfer extends AbstractAdapter 41 | { 42 | /** 43 | * Connects the AbstractTransport object and performs initial actions on the remote 44 | * server. 45 | * 46 | * @throws Ts3Exception 47 | * @return void 48 | */ 49 | public function syn() 50 | { 51 | $this->initTransport($this->options); 52 | $this->transport->setAdapter($this); 53 | 54 | Profiler::init(spl_object_hash($this)); 55 | 56 | Signal::getInstance()->emit("filetransferConnected", $this); 57 | } 58 | 59 | /** 60 | * The FileTransfer destructor. 61 | * 62 | * @return void 63 | */ 64 | public function __destruct() 65 | { 66 | if ($this->getTransport() instanceof AbstractTransport && $this->getTransport()->isConnected()) { 67 | $this->getTransport()->disconnect(); 68 | } 69 | } 70 | 71 | /** 72 | * Sends a valid file transfer key to the server to initialize the file transfer. 73 | * 74 | * @param string $ftkey 75 | * @throws Ts3Exception 76 | * @return void 77 | */ 78 | protected function init($ftkey) 79 | { 80 | if (strlen($ftkey) != 32) { 81 | throw new Ts3Exception("invalid file transfer key format"); 82 | } 83 | 84 | $this->getProfiler()->start(); 85 | $this->getTransport()->send($ftkey); 86 | 87 | Signal::getInstance()->emit("filetransferHandshake", $this); 88 | } 89 | 90 | /** 91 | * Sends the content of a file to the server. 92 | * 93 | * @param string $ftkey 94 | * @param integer $seek 95 | * @param string $data 96 | * @throws Ts3Exception 97 | * @return void 98 | */ 99 | public function upload($ftkey, $seek, $data) 100 | { 101 | $this->init($ftkey); 102 | 103 | $size = strlen($data); 104 | $seek = intval($seek); 105 | $pack = 4096; 106 | 107 | Signal::getInstance()->emit("filetransferUploadStarted", $ftkey, $seek, $size); 108 | 109 | for (; $seek < $size;) { 110 | $rest = $size - $seek; 111 | $pack = $rest < $pack ? $rest : $pack; 112 | $buff = substr($data, $seek, $pack); 113 | $seek = $seek + $pack; 114 | 115 | $this->getTransport()->send($buff); 116 | 117 | Signal::getInstance()->emit("filetransferUploadProgress", $ftkey, $seek, $size); 118 | } 119 | 120 | $this->getProfiler()->stop(); 121 | 122 | Signal::getInstance()->emit("filetransferUploadFinished", $ftkey, $seek, $size); 123 | 124 | if ($seek < $size) { 125 | throw new Ts3Exception( 126 | "incomplete file upload (" . $seek . " of " . $size . " bytes)" 127 | ); 128 | } 129 | } 130 | 131 | /** 132 | * Returns the content of a downloaded file as a String object. 133 | * 134 | * @param string $ftkey 135 | * @param integer $size 136 | * @param boolean $passthru 137 | * @throws Ts3Exception 138 | * @return StringHelper|void 139 | */ 140 | public function download($ftkey, $size, $passthru = false) 141 | { 142 | $this->init($ftkey); 143 | 144 | if ($passthru) { 145 | return $this->passthru($size); 146 | } 147 | 148 | $buff = new StringHelper(""); 149 | $size = intval($size); 150 | $pack = 4096; 151 | 152 | Signal::getInstance()->emit("filetransferDownloadStarted", $ftkey, count($buff), $size); 153 | 154 | for ($seek = 0; $seek < $size;) { 155 | $rest = $size - $seek; 156 | $pack = $rest < $pack ? $rest : $pack; 157 | $data = $this->getTransport()->read($rest < $pack ? $rest : $pack); 158 | $seek = $seek + $pack; 159 | 160 | $buff->append($data); 161 | 162 | Signal::getInstance()->emit("filetransferDownloadProgress", $ftkey, count($buff), $size); 163 | } 164 | 165 | $this->getProfiler()->stop(); 166 | 167 | Signal::getInstance()->emit("filetransferDownloadFinished", $ftkey, count($buff), $size); 168 | 169 | if (strlen($buff) != $size) { 170 | throw new Ts3Exception( 171 | "incomplete file download (" . count($buff) . " of " . $size . " bytes)" 172 | ); 173 | } 174 | 175 | return $buff; 176 | } 177 | 178 | /** 179 | * Outputs all remaining data on a TeamSpeak 3 file transfer stream using PHP's fpassthru() 180 | * function. 181 | * 182 | * @param integer $size 183 | * @throws Ts3Exception 184 | * @return void 185 | */ 186 | protected function passthru($size) 187 | { 188 | $buff_size = fpassthru($this->getTransport()->getStream()); 189 | 190 | if ($buff_size != $size) { 191 | throw new Ts3Exception( 192 | "incomplete file download (" . intval($buff_size) . " of " . $size . " bytes)" 193 | ); 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /TeamSpeak3/Adapter/ServerQuery.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Adapter; 29 | 30 | use TeamSpeak3\TeamSpeak3; 31 | use TeamSpeak3\Ts3Exception; 32 | use TeamSpeak3\Adapter\ServerQuery\Event; 33 | use TeamSpeak3\Adapter\ServerQuery\Reply; 34 | use TeamSpeak3\Node\Host; 35 | use TeamSpeak3\Helper\Profiler; 36 | use TeamSpeak3\Helper\Signal; 37 | use TeamSpeak3\Transport\AbstractTransport; 38 | use TeamSpeak3\Helper\StringHelper; 39 | use TeamSpeak3\Node\AbstractNode; 40 | 41 | /** 42 | * @class ServerQuery 43 | * @brief Provides low-level methods for ServerQuery communication with a TeamSpeak 3 Server. 44 | */ 45 | class ServerQuery extends AbstractAdapter 46 | { 47 | /** 48 | * Stores a singleton instance of the active Host object. 49 | * 50 | * @var Host 51 | */ 52 | protected $host = null; 53 | 54 | /** 55 | * Stores the timestamp of the last command. 56 | * 57 | * @var integer 58 | */ 59 | protected $timer = null; 60 | 61 | /** 62 | * Number of queries executed on the server. 63 | * 64 | * @var integer 65 | */ 66 | protected $count = 0; 67 | 68 | /** 69 | * Stores an array with unsupported commands. 70 | * 71 | * @var array 72 | */ 73 | protected $block = array("help"); 74 | 75 | /** 76 | * Connects the AbstractTransport object and performs initial actions on the remote 77 | * server. 78 | * 79 | * @throws Ts3Exception 80 | * @return void 81 | */ 82 | protected function syn() 83 | { 84 | $this->initTransport($this->options); 85 | $this->transport->setAdapter($this); 86 | 87 | Profiler::init(spl_object_hash($this)); 88 | 89 | if (!$this->getTransport()->readLine()->startsWith(TeamSpeak3::READY)) { 90 | throw new Ts3Exception("invalid reply from the server"); 91 | } 92 | 93 | Signal::getInstance()->emit("serverqueryConnected", $this); 94 | } 95 | 96 | /** 97 | * The ServerQuery destructor. 98 | * 99 | * @return void 100 | */ 101 | public function __destruct() 102 | { 103 | if ($this->getTransport() instanceof AbstractTransport && $this->transport->isConnected()) { 104 | try { 105 | $this->request("quit"); 106 | } catch (Ts3Exception $e) { 107 | return; 108 | } 109 | } 110 | } 111 | 112 | /** 113 | * Sends a prepared command to the server and returns the result. 114 | * 115 | * @param string $cmd 116 | * @param boolean $throw 117 | * @throws Ts3Exception 118 | * @throws Ts3Exception 119 | * @return Reply 120 | */ 121 | public function request($cmd, $throw = true) 122 | { 123 | $query = StringHelper::factory($cmd)->section(TeamSpeak3::SEPARATOR_CELL); 124 | 125 | if (strstr($cmd, "\r") || strstr($cmd, "\n")) { 126 | throw new Ts3Exception("illegal characters in command '" . $query . "'"); 127 | } elseif (in_array($query, $this->block)) { 128 | throw new Ts3Exception("command not found", 0x100); 129 | } 130 | 131 | Signal::getInstance()->emit("serverqueryCommandStarted", $cmd); 132 | 133 | $this->getProfiler()->start(); 134 | $this->getTransport()->sendLine($cmd); 135 | $this->timer = time(); 136 | $this->count++; 137 | 138 | $rpl = array(); 139 | 140 | do { 141 | $str = $this->getTransport()->readLine(); 142 | $rpl[] = $str; 143 | } while ($str instanceof StringHelper && $str->section( 144 | TeamSpeak3::SEPARATOR_CELL 145 | ) != TeamSpeak3::ERROR); 146 | 147 | $this->getProfiler()->stop(); 148 | 149 | $reply = new Reply($rpl, $cmd, $this->getHost(), $throw); 150 | 151 | Signal::getInstance()->emit("serverqueryCommandFinished", $cmd, $reply); 152 | 153 | return $reply; 154 | } 155 | 156 | /** 157 | * Waits for the server to send a notification message and returns the result. 158 | * 159 | * @throws Ts3Exception 160 | * @return Event 161 | */ 162 | public function wait() 163 | { 164 | if ($this->getTransport()->getConfig("blocking")) { 165 | throw new Ts3Exception("only available in non-blocking mode"); 166 | } 167 | 168 | do { 169 | $evt = $this->getTransport()->readLine(); 170 | var_dump($evt); 171 | } while ($evt instanceof StringHelper && 172 | !$evt->section(TeamSpeak3::SEPARATOR_CELL)->startsWith(TeamSpeak3::EVENT)); 173 | 174 | return new Event($evt, $this->getHost()); 175 | } 176 | 177 | /** 178 | * Uses given parameters and returns a prepared ServerQuery command. 179 | * 180 | * @param string $cmd 181 | * @param array $params 182 | * @return string 183 | */ 184 | public function prepare($cmd, array $params = array()) 185 | { 186 | $args = array(); 187 | $cells = array(); 188 | 189 | foreach ($params as $ident => $value) { 190 | $ident = is_numeric($ident) ? "" : strtolower($ident) . TeamSpeak3::SEPARATOR_PAIR; 191 | 192 | if (is_array($value)) { 193 | $value = array_values($value); 194 | 195 | for ($i = 0; $i < count($value); $i++) { 196 | if ($value[$i] === null) { 197 | continue; 198 | } elseif ($value[$i] === false) { 199 | $value[$i] = 0x00; 200 | } elseif ($value[$i] === true) { 201 | $value[$i] = 0x01; 202 | } elseif ($value[$i] instanceof AbstractNode) { 203 | $value[$i] = $value[$i]->getId(); 204 | } 205 | 206 | $cells[$i][] = $ident . StringHelper::factory($value[$i])->escape()->toUtf8(); 207 | } 208 | } else { 209 | if ($value === null) { 210 | continue; 211 | } elseif ($value === false) { 212 | $value = 0x00; 213 | } elseif ($value === true) { 214 | $value = 0x01; 215 | } elseif ($value instanceof AbstractNode) { 216 | $value = $value->getId(); 217 | } 218 | 219 | $args[] = $ident . StringHelper::factory($value)->escape()->toUtf8(); 220 | } 221 | } 222 | 223 | foreach (array_keys($cells) as $ident) { 224 | $cells[$ident] = implode(TeamSpeak3::SEPARATOR_CELL, $cells[$ident]); 225 | } 226 | 227 | if (count($args)) { 228 | $cmd .= " " . implode(TeamSpeak3::SEPARATOR_CELL, $args); 229 | } 230 | if (count($cells)) { 231 | $cmd .= " " . implode(TeamSpeak3::SEPARATOR_LIST, $cells); 232 | } 233 | 234 | return trim($cmd); 235 | } 236 | 237 | /** 238 | * Returns the timestamp of the last command. 239 | * 240 | * @return integer 241 | */ 242 | public function getQueryLastTimestamp() 243 | { 244 | return $this->timer; 245 | } 246 | 247 | /** 248 | * Returns the number of queries executed on the server. 249 | * 250 | * @return integer 251 | */ 252 | public function getQueryCount() 253 | { 254 | return $this->count; 255 | } 256 | 257 | /** 258 | * Returns the total runtime of all queries. 259 | * 260 | * @return mixed 261 | */ 262 | public function getQueryRuntime() 263 | { 264 | return $this->getProfiler()->getRuntime(); 265 | } 266 | 267 | /** 268 | * Returns the Host object of the current connection. 269 | * 270 | * @return Host 271 | */ 272 | public function getHost() 273 | { 274 | if ($this->host === null) { 275 | $this->host = new Host($this); 276 | } 277 | 278 | return $this->host; 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /TeamSpeak3/Adapter/ServerQuery/Event.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Adapter\ServerQuery; 29 | 30 | use TeamSpeak3\Helper\StringHelper; 31 | use TeamSpeak3\Node\Host; 32 | use TeamSpeak3\TeamSpeak3; 33 | use TeamSpeak3\Helper\Signal; 34 | use TeamSpeak3\Ts3Exception; 35 | 36 | use ArrayAccess; 37 | 38 | /** 39 | * @class Event 40 | * @brief Provides methods to analyze and format a ServerQuery event. 41 | */ 42 | class Event implements ArrayAccess 43 | { 44 | /** 45 | * Stores the event type. 46 | * 47 | * @var StringHelper 48 | */ 49 | protected $type = null; 50 | 51 | /** 52 | * Stores the event data. 53 | * 54 | * @var array 55 | */ 56 | protected $data = null; 57 | 58 | /** 59 | * Stores the event data as an unparsed string. 60 | * 61 | * @var StringHelper 62 | */ 63 | protected $mesg = null; 64 | 65 | /** 66 | * Creates a new Event object. 67 | * 68 | * @param StringHelper $evt 69 | * @param Host $con 70 | * @throws Ts3Exception 71 | * @return Event 72 | */ 73 | public function __construct(StringHelper $evt, Host $con = null) 74 | { 75 | if (!$evt->startsWith(TeamSpeak3::EVENT)) { 76 | throw new Ts3Exception("invalid notification event format"); 77 | } 78 | 79 | list($type, $data) = $evt->split(TeamSpeak3::SEPARATOR_CELL, 2); 80 | 81 | if (empty($data)) { 82 | throw new Ts3Exception("invalid notification event data"); 83 | } 84 | 85 | $fake = new StringHelper( 86 | TeamSpeak3::ERROR . TeamSpeak3::SEPARATOR_CELL . "id" . TeamSpeak3::SEPARATOR_PAIR . 0 . TeamSpeak3::SEPARATOR_CELL . "msg" . TeamSpeak3::SEPARATOR_PAIR . "ok" 87 | ); 88 | $repl = new Reply(array($data, $fake), $type); 89 | 90 | $this->type = $type->substr(strlen(TeamSpeak3::EVENT)); 91 | $this->data = $repl->toList(); 92 | $this->mesg = $data; 93 | 94 | Signal::getInstance()->emit("notifyEvent", $this, $con); 95 | Signal::getInstance()->emit("notify" . ucfirst($this->type), $this, $con); 96 | } 97 | 98 | /** 99 | * Returns the event type string. 100 | * 101 | * @return StringHelper 102 | */ 103 | public function getType() 104 | { 105 | return $this->type; 106 | } 107 | 108 | /** 109 | * Returns the event data array. 110 | * 111 | * @return array 112 | */ 113 | public function getData() 114 | { 115 | return $this->data; 116 | } 117 | 118 | /** 119 | * Returns the event data as an unparsed string. 120 | * 121 | * @return StringHelper 122 | */ 123 | public function getMessage() 124 | { 125 | return $this->mesg; 126 | } 127 | 128 | /** 129 | * @ignore 130 | */ 131 | public function offsetExists($offset) 132 | { 133 | return array_key_exists($offset, $this->data) ? true : false; 134 | } 135 | 136 | /** 137 | * @ignore 138 | */ 139 | public function offsetGet($offset) 140 | { 141 | if (!$this->offsetExists($offset)) { 142 | throw new Ts3Exception("invalid parameter", 0x602); 143 | } 144 | 145 | return $this->data[$offset]; 146 | } 147 | 148 | /** 149 | * @ignore 150 | */ 151 | public function offsetSet($offset, $value) 152 | { 153 | throw new Ts3Exception("event '" . $this->getType() . "' is read only"); 154 | } 155 | 156 | /** 157 | * @ignore 158 | */ 159 | public function offsetUnset($offset) 160 | { 161 | unset($this->data[$offset]); 162 | } 163 | 164 | /** 165 | * @ignore 166 | */ 167 | public function __get($offset) 168 | { 169 | return $this->offsetGet($offset); 170 | } 171 | 172 | /** 173 | * @ignore 174 | */ 175 | public function __set($offset, $value) 176 | { 177 | $this->offsetSet($offset, $value); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /TeamSpeak3/Adapter/ServerQuery/Reply.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Adapter\ServerQuery; 29 | 30 | use TeamSpeak3\Helper\StringHelper; 31 | use TeamSpeak3\Node\Host; 32 | use TeamSpeak3\TeamSpeak3; 33 | use TeamSpeak3\Ts3Exception; 34 | use TeamSpeak3\Helper\Signal; 35 | use \ArrayObject; 36 | 37 | 38 | /** 39 | * @class Reply 40 | * @brief Provides methods to analyze and format a ServerQuery reply. 41 | */ 42 | class Reply 43 | { 44 | /** 45 | * Stores the command used to get this reply. 46 | * 47 | * @var StringHelper 48 | */ 49 | protected $cmd = null; 50 | 51 | /** 52 | * Stores the servers reply (if available). 53 | * 54 | * @var StringHelper 55 | */ 56 | protected $rpl = null; 57 | 58 | /** 59 | * Stores connected Host object. 60 | * 61 | * @var Host 62 | */ 63 | protected $con = null; 64 | 65 | /** 66 | * Stores an assoc array containing the error info for this reply. 67 | * 68 | * @var array 69 | */ 70 | protected $err = array(); 71 | 72 | /** 73 | * Sotres an array of events that occured before or during this reply. 74 | * 75 | * @var array 76 | */ 77 | protected $evt = array(); 78 | 79 | /** 80 | * Indicates whether exceptions should be thrown or not. 81 | * 82 | * @var boolean 83 | */ 84 | protected $exp = true; 85 | 86 | /** 87 | * Creates a new Reply object. 88 | * 89 | * @param array $rpl 90 | * @param string $cmd 91 | * @param boolean $exp 92 | * @param Host $con 93 | * @return Reply 94 | */ 95 | public function __construct(array $rpl, $cmd = null, Host $con = null, $exp = true) 96 | { 97 | $this->cmd = new StringHelper($cmd); 98 | $this->con = $con; 99 | $this->exp = (bool)$exp; 100 | 101 | $this->fetchError(array_pop($rpl)); 102 | $this->fetchReply($rpl); 103 | } 104 | 105 | /** 106 | * Returns the reply as an String object. 107 | * 108 | * @return StringHelper 109 | */ 110 | public function toString() 111 | { 112 | return (!func_num_args()) ? $this->rpl->unescape() : $this->rpl; 113 | } 114 | 115 | /** 116 | * Returns the reply as a standard PHP array where each element represents one item. 117 | * 118 | * @return array 119 | */ 120 | public function toLines() 121 | { 122 | if (!count($this->rpl)) { 123 | return array(); 124 | } 125 | 126 | $list = $this->toString(0)->split(TeamSpeak3::SEPARATOR_LIST); 127 | 128 | if (!func_num_args()) { 129 | for ($i = 0; $i < count($list); $i++) { 130 | $list[$i]->unescape(); 131 | } 132 | } 133 | 134 | return $list; 135 | } 136 | 137 | /** 138 | * Returns the reply as a standard PHP array where each element represents one item in table format. 139 | * 140 | * @return array 141 | */ 142 | public function toTable() 143 | { 144 | $table = array(); 145 | 146 | foreach ($this->toLines(0) as $cells) { 147 | $pairs = $cells->split(TeamSpeak3::SEPARATOR_CELL); 148 | 149 | if (!func_num_args()) { 150 | for ($i = 0; $i < count($pairs); $i++) { 151 | $pairs[$i]->unescape(); 152 | } 153 | } 154 | 155 | $table[] = $pairs; 156 | } 157 | 158 | return $table; 159 | } 160 | 161 | /** 162 | * Returns a multi-dimensional array containing the reply splitted in multiple rows and columns. 163 | * 164 | * @return array 165 | */ 166 | public function toArray() 167 | { 168 | $array = array(); 169 | $table = $this->toTable(1); 170 | 171 | for ($i = 0; $i < count($table); $i++) { 172 | foreach ($table[$i] as $pair) { 173 | if (!count($pair)) { 174 | continue; 175 | } 176 | 177 | if (!$pair->contains(TeamSpeak3::SEPARATOR_PAIR)) { 178 | $array[$i][$pair->toString()] = null; 179 | } else { 180 | list($ident, $value) = $pair->split(TeamSpeak3::SEPARATOR_PAIR, 2); 181 | 182 | if($ident == 'msg') 183 | $array[$i][$ident->toString()] = new StringHelper($value->unescape()); 184 | else 185 | $array[$i][$ident->toString()] = $value->isInt() ? $value->toInt() : (!func_num_args() ? $value->unescape() : $value); 186 | } 187 | } 188 | } 189 | 190 | return $array; 191 | } 192 | 193 | /** 194 | * Returns a multi-dimensional assoc array containing the reply splitted in multiple rows and columns. 195 | * The identifier specified by key will be used while indexing the array. 196 | * 197 | * @param $ident 198 | * @throws Ts3Exception 199 | * @return array 200 | */ 201 | public function toAssocArray($ident) 202 | { 203 | $nodes = (func_num_args() > 1) ? $this->toArray(1) : $this->toArray(); 204 | $array = array(); 205 | 206 | foreach ($nodes as $node) { 207 | if (array_key_exists($ident, $node)) { 208 | $array[(is_object($node[$ident])) ? $node[$ident]->toString() : $node[$ident]] = $node; 209 | } else { 210 | throw new Ts3Exception("invalid parameter", 0x602); 211 | } 212 | } 213 | 214 | return $array; 215 | } 216 | 217 | /** 218 | * Returns an array containing the reply splitted in multiple rows and columns. 219 | * 220 | * @return array 221 | */ 222 | public function toList() 223 | { 224 | $array = func_num_args() ? $this->toArray(1) : $this->toArray(); 225 | 226 | if (count($array) == 1) { 227 | return array_shift($array); 228 | } 229 | 230 | return $array; 231 | } 232 | 233 | /** 234 | * Returns an array containing stdClass objects. 235 | * 236 | * @return ArrayObject 237 | */ 238 | public function toObjectArray() 239 | { 240 | $array = (func_num_args() > 1) ? $this->toArray(1) : $this->toArray(); 241 | 242 | for ($i = 0; $i < count($array); $i++) { 243 | $array[$i] = (object)$array[$i]; 244 | } 245 | 246 | return $array; 247 | } 248 | 249 | /** 250 | * Returns the command used to get this reply. 251 | * 252 | * @return StringHelper 253 | */ 254 | public function getCommandString() 255 | { 256 | return new StringHelper($this->cmd); 257 | } 258 | 259 | /** 260 | * Returns an array of events that occured before or during this reply. 261 | * 262 | * @return array 263 | */ 264 | public function getNotifyEvents() 265 | { 266 | return $this->evt; 267 | } 268 | 269 | /** 270 | * Returns the value for a specified error property. 271 | * 272 | * @param string $ident 273 | * @param mixed $default 274 | * @return mixed 275 | */ 276 | public function getErrorProperty($ident, $default = null) 277 | { 278 | return (array_key_exists($ident, $this->err)) ? $this->err[$ident] : $default; 279 | } 280 | 281 | /** 282 | * Parses a ServerQuery error and throws a Ts3Exception object if 283 | * there's an error. 284 | * 285 | * @param StringHelper|string $err 286 | * @throws Ts3Exception 287 | * @return void 288 | */ 289 | protected function fetchError($err) 290 | { 291 | $cells = $err->section(TeamSpeak3::SEPARATOR_CELL, 1, 3); 292 | 293 | foreach ($cells->split(TeamSpeak3::SEPARATOR_CELL) as $pair) { 294 | list($ident, $value) = $pair->split(TeamSpeak3::SEPARATOR_PAIR); 295 | 296 | $this->err[$ident->toString()] = $value->isInt() ? $value->toInt() : $value->unescape(); 297 | } 298 | 299 | Signal::getInstance()->emit("notifyError", $this); 300 | 301 | if ($this->getErrorProperty("id", 0x00) != 0x00 && $this->exp) { 302 | if ($permid = $this->getErrorProperty("failed_permid")) { 303 | if ($permsid = key($this->con->request("permget permid=" . $permid, false)->toAssocArray("permsid"))) { 304 | $suffix = " (failed on " . $permsid . ")"; 305 | } else { 306 | $suffix = " (failed on " . $this->cmd->section( 307 | TeamSpeak3::SEPARATOR_CELL 308 | ) . " " . $permid . "/0x" . strtoupper(dechex($permid)) . ")"; 309 | } 310 | } elseif ($details = $this->getErrorProperty("extra_msg")) { 311 | $suffix = " (" . trim($details) . ")"; 312 | } else { 313 | $suffix = ""; 314 | } 315 | 316 | throw new Ts3Exception( 317 | $this->getErrorProperty("msg") . $suffix, 318 | $this->getErrorProperty("id") 319 | ); 320 | } 321 | } 322 | 323 | /** 324 | * Parses a ServerQuery reply and creates a String object. 325 | * 326 | * @param array $rpl 327 | * @return void 328 | */ 329 | protected function fetchReply($rpl) 330 | { 331 | foreach ($rpl as $key => $val) { 332 | if ($val->startsWith(TeamSpeak3::GREET)) { 333 | unset($rpl[$key]); 334 | } elseif ($val->startsWith(TeamSpeak3::EVENT)) { 335 | $this->evt[] = new Event($rpl[$key], $this->con); 336 | unset($rpl[$key]); 337 | } 338 | } 339 | 340 | $this->rpl = new StringHelper(implode(TeamSpeak3::SEPARATOR_LIST, $rpl)); 341 | } 342 | } 343 | -------------------------------------------------------------------------------- /TeamSpeak3/Adapter/TSDNS.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Adapter; 29 | 30 | use TeamSpeak3\Helper\Profiler; 31 | use TeamSpeak3\Helper\Signal; 32 | use TeamSpeak3\Transport\AbstractTransport; 33 | use TeamSpeak3\Ts3Exception; 34 | use TeamSpeak3\Helper\StringHelper; 35 | 36 | /** 37 | * @class TSDNS 38 | * @brief Provides methods to query a TSDNS server. 39 | */ 40 | class TSDNS extends AbstractAdapter 41 | { 42 | /** 43 | * The TCP port number used by any TSDNS server. 44 | * 45 | * @var integer 46 | */ 47 | protected $default_port = 41144; 48 | 49 | /** 50 | * Connects the AbstractTransport object and performs initial actions on the remote 51 | * server. 52 | * 53 | * @throws Ts3Exception 54 | * @return void 55 | */ 56 | public function syn() 57 | { 58 | if (!isset($this->options["port"]) || empty($this->options["port"])) { 59 | $this->options["port"] = $this->default_port; 60 | } 61 | 62 | $this->initTransport($this->options); 63 | $this->transport->setAdapter($this); 64 | 65 | Profiler::init(spl_object_hash($this)); 66 | 67 | Signal::getInstance()->emit("tsdnsConnected", $this); 68 | } 69 | 70 | /** 71 | * The FileTransfer destructor. 72 | * 73 | * @return void 74 | */ 75 | public function __destruct() 76 | { 77 | if ($this->getTransport() instanceof AbstractTransport && $this->getTransport()->isConnected()) { 78 | $this->getTransport()->disconnect(); 79 | } 80 | } 81 | 82 | /** 83 | * Queries the TSDNS server for a specified virtual hostname and returns the result. 84 | * 85 | * @param StringHelper|string $tsdns 86 | * @throws Ts3Exception 87 | * @return StringHelper 88 | */ 89 | public function resolve($tsdns) 90 | { 91 | $this->getTransport()->sendLine($tsdns); 92 | $repl = $this->getTransport()->readLine(); 93 | $this->getTransport()->disconnect(); 94 | 95 | if ($repl->section(":", 0)->toInt() == 404) { 96 | throw new Ts3Exception("unable to resolve TSDNS hostname (" . $tsdns . ")"); 97 | } 98 | 99 | Signal::getInstance()->emit("tsdnsResolved", $tsdns, $repl); 100 | 101 | return $repl; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /TeamSpeak3/Adapter/Update.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Adapter; 29 | 30 | use TeamSpeak3\Ts3Exception; 31 | use TeamSpeak3\Helper\Profiler; 32 | use TeamSpeak3\Helper\Signal; 33 | use TeamSpeak3\Helper\StringHelper; 34 | use TeamSpeak3\Transport\AbstractTransport; 35 | 36 | 37 | /** 38 | * @class Update 39 | * @brief Provides methods to query the latest TeamSpeak 3 build numbers from the master server. 40 | */ 41 | class Update extends AbstractAdapter 42 | { 43 | /** 44 | * The IPv4 address or FQDN of the TeamSpeak Systems update server. 45 | * 46 | * @var string 47 | */ 48 | protected $default_host = "update.teamspeak.com"; 49 | 50 | /** 51 | * The UDP port number of the TeamSpeak Systems update server. 52 | * 53 | * @var integer 54 | */ 55 | protected $default_port = 17384; 56 | 57 | /** 58 | * Stores an array containing the latest build numbers (integer timestamps). 59 | * 60 | * @var array 61 | */ 62 | protected $build_datetimes = null; 63 | 64 | /** 65 | * Stores an array containing the latest version strings. 66 | * 67 | * @var array 68 | */ 69 | protected $version_strings = null; 70 | 71 | /** 72 | * Connects the AbstractTransport object and performs initial actions on the remote 73 | * server. 74 | * 75 | * @throws Ts3Exception 76 | * @return void 77 | */ 78 | public function syn() 79 | { 80 | if (!isset($this->options["host"]) || empty($this->options["host"])) { 81 | $this->options["host"] = $this->default_host; 82 | } 83 | if (!isset($this->options["port"]) || empty($this->options["port"])) { 84 | $this->options["port"] = $this->default_port; 85 | } 86 | 87 | $this->initTransport($this->options, "UDP"); 88 | $this->transport->setAdapter($this); 89 | 90 | Profiler::init(spl_object_hash($this)); 91 | 92 | $this->getTransport()->send(StringHelper::fromHex(33)); 93 | 94 | if (!preg_match_all( 95 | "/,?(\d+)#([0-9a-zA-Z\._-]+),?/", 96 | $this->getTransport()->read(96), 97 | $matches 98 | ) || !isset($matches[1]) || !isset($matches[2]) 99 | ) { 100 | throw new Ts3Exception("invalid reply from the server"); 101 | } 102 | 103 | $this->build_datetimes = $matches[1]; 104 | $this->version_strings = $matches[2]; 105 | 106 | Signal::getInstance()->emit("updateConnected", $this); 107 | } 108 | 109 | /** 110 | * The Update destructor. 111 | * 112 | * @return void 113 | */ 114 | public function __destruct() 115 | { 116 | if ($this->getTransport() instanceof AbstractTransport && $this->getTransport()->isConnected()) { 117 | $this->getTransport()->disconnect(); 118 | } 119 | } 120 | 121 | /** 122 | * Returns the current build number for a specified update channel. Note that since version 123 | * 3.0.0, the build number represents an integer timestamp. $channel must be set to one of 124 | * the following values: 125 | * 126 | * - stable 127 | * - beta 128 | * - alpha 129 | * - server 130 | * 131 | * @param string $channel 132 | * @throws Ts3Exception 133 | * @return integer 134 | */ 135 | public function getRev($channel = "stable") 136 | { 137 | switch ($channel) { 138 | case "stable": 139 | return isset($this->build_datetimes[0]) ? $this->build_datetimes[0] : null; 140 | 141 | case "beta": 142 | return isset($this->build_datetimes[1]) ? $this->build_datetimes[1] : null; 143 | 144 | case "alpha": 145 | return isset($this->build_datetimes[2]) ? $this->build_datetimes[2] : null; 146 | 147 | case "server": 148 | return isset($this->build_datetimes[3]) ? $this->build_datetimes[3] : null; 149 | 150 | default: 151 | throw new Ts3Exception("invalid update channel identifier (" . $channel . ")"); 152 | } 153 | } 154 | 155 | /** 156 | * Returns the current version string for a specified update channel. $channel must be set to 157 | * one of the following values: 158 | * 159 | * - stable 160 | * - beta 161 | * - alpha 162 | * - server 163 | * 164 | * @param string $channel 165 | * @throws Ts3Exception 166 | * @return integer 167 | */ 168 | public function getVersion($channel = "stable") 169 | { 170 | switch ($channel) { 171 | case "stable": 172 | return isset($this->version_strings[0]) ? $this->version_strings[0] : null; 173 | 174 | case "beta": 175 | return isset($this->version_strings[1]) ? $this->version_strings[1] : null; 176 | 177 | case "alpha": 178 | return isset($this->version_strings[2]) ? $this->version_strings[2] : null; 179 | 180 | case "server": 181 | return isset($this->version_strings[3]) ? $this->version_strings[3] : null; 182 | 183 | default: 184 | throw new Ts3Exception("invalid update channel identifier (" . $channel . ")"); 185 | } 186 | } 187 | 188 | /** 189 | * Alias for getRev() using the 'stable' update channel. 190 | * 191 | * @internal param string $channel 192 | * @return integer 193 | */ 194 | public function getClientRev() 195 | { 196 | return $this->getRev("stable"); 197 | } 198 | 199 | /** 200 | * Alias for getRev() using the 'server' update channel. 201 | * 202 | * @return integer 203 | */ 204 | public function getServerRev() 205 | { 206 | return $this->getRev("server"); 207 | } 208 | 209 | /** 210 | * Alias for getVersion() using the 'stable' update channel. 211 | * 212 | * @return integer 213 | */ 214 | public function getClientVersion() 215 | { 216 | return $this->getVersion("stable"); 217 | } 218 | 219 | /** 220 | * Alias for getVersion() using the 'server' update channel. 221 | * 222 | * @return integer 223 | */ 224 | public function getServerVersion() 225 | { 226 | return $this->getVersion("server"); 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /TeamSpeak3/Helper/Char.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Helper; 29 | 30 | use TeamSpeak3\Ts3Exception; 31 | 32 | /** 33 | * @class Char 34 | * @brief Helper class for char handling. 35 | */ 36 | class Char 37 | { 38 | /** 39 | * Stores the original character. 40 | * 41 | * @var string 42 | */ 43 | protected $char = null; 44 | 45 | /** 46 | * The Char constructor. 47 | * 48 | * @param $char 49 | * @throws Ts3Exception 50 | * @internal param string $var 51 | * @return Char 52 | */ 53 | public function __construct($char) 54 | { 55 | if (strlen($char) != 1) { 56 | throw new Ts3Exception("char parameter may not contain more or less than one character"); 57 | } 58 | 59 | $this->char = strval($char); 60 | } 61 | 62 | /** 63 | * Returns true if the character is a letter. 64 | * 65 | * @return boolean 66 | */ 67 | public function isLetter() 68 | { 69 | return ctype_alpha($this->char); 70 | } 71 | 72 | /** 73 | * Returns true if the character is a decimal digit. 74 | * 75 | * @return boolean 76 | */ 77 | public function isDigit() 78 | { 79 | return ctype_digit($this->char); 80 | } 81 | 82 | /** 83 | * Returns true if the character is a space. 84 | * 85 | * @return boolean 86 | */ 87 | public function isSpace() 88 | { 89 | return ctype_space($this->char); 90 | } 91 | 92 | /** 93 | * Returns true if the character is a mark. 94 | * 95 | * @return boolean 96 | */ 97 | public function isMark() 98 | { 99 | return ctype_punct($this->char); 100 | } 101 | 102 | /** 103 | * Returns true if the character is a control character (i.e. "\t"). 104 | * 105 | * @return boolean 106 | */ 107 | public function isControl() 108 | { 109 | return ctype_cntrl($this->char); 110 | } 111 | 112 | /** 113 | * Returns true if the character is a printable character. 114 | * 115 | * @return boolean 116 | */ 117 | public function isPrintable() 118 | { 119 | return ctype_print($this->char); 120 | } 121 | 122 | /** 123 | * Returns true if the character is the Unicode character 0x0000 ("\0"). 124 | * 125 | * @return boolean 126 | */ 127 | public function isNull() 128 | { 129 | return ($this->char === "\0") ? true : false; 130 | } 131 | 132 | /** 133 | * Returns true if the character is an uppercase letter. 134 | * 135 | * @return boolean 136 | */ 137 | public function isUpper() 138 | { 139 | return ($this->char === strtoupper($this->char)) ? true : false; 140 | } 141 | 142 | /** 143 | * Returns true if the character is a lowercase letter. 144 | * 145 | * @return boolean 146 | */ 147 | public function isLower() 148 | { 149 | return ($this->char === strtolower($this->char)) ? true : false; 150 | } 151 | 152 | /** 153 | * Returns the uppercase equivalent if the character is lowercase. 154 | * 155 | * @return Char 156 | */ 157 | public function toUpper() 158 | { 159 | return ($this->isUpper()) ? $this : new self(strtoupper($this)); 160 | } 161 | 162 | /** 163 | * Returns the lowercase equivalent if the character is uppercase. 164 | * 165 | * @return Char 166 | */ 167 | public function toLower() 168 | { 169 | return ($this->isLower()) ? $this : new self(strtolower($this)); 170 | } 171 | 172 | /** 173 | * Returns the ascii value of the character. 174 | * 175 | * @return integer 176 | */ 177 | public function toAscii() 178 | { 179 | return ord($this->char); 180 | } 181 | 182 | /** 183 | * Returns the Unicode value of the character. 184 | * 185 | * @return integer 186 | */ 187 | public function toUnicode() 188 | { 189 | $h = ord($this->char{0}); 190 | 191 | if ($h <= 0x7F) { 192 | return $h; 193 | } else { 194 | if ($h < 0xC2) { 195 | return false; 196 | } else { 197 | if ($h <= 0xDF) { 198 | return ($h & 0x1F) << 6 | (ord($this->char{1}) & 0x3F); 199 | } else { 200 | if ($h <= 0xEF) { 201 | return ($h & 0x0F) << 12 | (ord($this->char{1}) & 0x3F) << 6 | (ord($this->char{2}) & 0x3F); 202 | } else { 203 | if ($h <= 0xF4) { 204 | return ($h & 0x0F) << 18 | (ord($this->char{1}) & 0x3F) << 12 | (ord( 205 | $this->char{2} 206 | ) & 0x3F) << 6 | (ord( 207 | $this->char{3} 208 | ) & 0x3F); 209 | } else { 210 | return false; 211 | } 212 | } 213 | } 214 | } 215 | } 216 | } 217 | 218 | /** 219 | * Returns the hexadecimal value of the char. 220 | * 221 | * @return string 222 | */ 223 | public function toHex() 224 | { 225 | return strtoupper(dechex($this->toAscii())); 226 | } 227 | 228 | /** 229 | * Returns the Char based on a given hex value. 230 | * 231 | * @param string $hex 232 | * @throws Ts3Exception 233 | * @return Char 234 | */ 235 | public static function fromHex($hex) 236 | { 237 | if (strlen($hex) != 2) { 238 | throw new Ts3Exception("given parameter '" . $hex . "' is not a valid hexadecimal number"); 239 | } 240 | 241 | return new self(chr(hexdec($hex))); 242 | } 243 | 244 | /** 245 | * Returns the character as a standard string. 246 | * 247 | * @return string 248 | */ 249 | public function toString() 250 | { 251 | return $this->char; 252 | } 253 | 254 | /** 255 | * Returns the integer value of the character. 256 | * 257 | * @return integer 258 | */ 259 | public function toInt() 260 | { 261 | return intval($this->char); 262 | } 263 | 264 | /** 265 | * Returns the character as a standard string. 266 | * 267 | * @return string 268 | */ 269 | public function __toString() 270 | { 271 | return $this->char; 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /TeamSpeak3/Helper/Convert.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Helper; 29 | 30 | use TeamSpeak3\TeamSpeak3; 31 | 32 | 33 | /** 34 | * @class Convert 35 | * @brief Helper class for data conversion. 36 | */ 37 | class Convert 38 | { 39 | /** 40 | * Converts bytes to a human readable value. 41 | * 42 | * @param integer $bytes 43 | * @return string 44 | */ 45 | public static function bytes($bytes) 46 | { 47 | $kbytes = sprintf("%.02f", $bytes / 1024); 48 | $mbytes = sprintf("%.02f", $kbytes / 1024); 49 | $gbytes = sprintf("%.02f", $mbytes / 1024); 50 | $tbytes = sprintf("%.02f", $gbytes / 1024); 51 | 52 | if ($tbytes >= 1) { 53 | return $tbytes . " TB"; 54 | } 55 | if ($gbytes >= 1) { 56 | return $gbytes . " GB"; 57 | } 58 | if ($mbytes >= 1) { 59 | return $mbytes . " MB"; 60 | } 61 | if ($kbytes >= 1) { 62 | return $kbytes . " KB"; 63 | } 64 | 65 | return $bytes . " B"; 66 | } 67 | 68 | /** 69 | * Converts seconds/milliseconds to a human readable value. 70 | * 71 | * @param integer $seconds 72 | * @param boolean $is_ms 73 | * @param string $format 74 | * @return string 75 | */ 76 | public static function seconds($seconds, $is_ms = false, $format = "%dD %02d:%02d:%02d") 77 | { 78 | if ($is_ms) { 79 | $seconds = $seconds / 1000; 80 | } 81 | 82 | return sprintf( 83 | $format, 84 | $seconds / 60 / 60 / 24, 85 | ($seconds / 60 / 60) % 24, 86 | ($seconds / 60) % 60, 87 | $seconds % 60 88 | ); 89 | } 90 | 91 | /** 92 | * Converts a given codec ID to a human readable name. 93 | * 94 | * @param integer $codec 95 | * @return string 96 | */ 97 | public static function codec($codec) 98 | { 99 | if ($codec == TeamSpeak3::CODEC_SPEEX_NARROWBAND) { 100 | return "Speex Narrowband"; 101 | } 102 | if ($codec == TeamSpeak3::CODEC_SPEEX_WIDEBAND) { 103 | return "Speex Wideband"; 104 | } 105 | if ($codec == TeamSpeak3::CODEC_SPEEX_ULTRAWIDEBAND) { 106 | return "Speex Ultra-Wideband"; 107 | } 108 | if ($codec == TeamSpeak3::CODEC_CELT_MONO) { 109 | return "CELT Mono"; 110 | } 111 | if ($codec == TeamSpeak3::CODEC_OPUS_VOICE) { 112 | return "Opus Voice"; 113 | } 114 | if ($codec == TeamSpeak3::CODEC_OPUS_MUSIC) { 115 | return "Opus Music"; 116 | } 117 | 118 | return "Unknown"; 119 | } 120 | 121 | /** 122 | * Converts a given group type ID to a human readable name. 123 | * 124 | * @param integer $type 125 | * @return string 126 | */ 127 | public static function groupType($type) 128 | { 129 | if ($type == TeamSpeak3::GROUP_DBTYPE_TEMPLATE) { 130 | return "Template"; 131 | } 132 | if ($type == TeamSpeak3::GROUP_DBTYPE_REGULAR) { 133 | return "Regular"; 134 | } 135 | if ($type == TeamSpeak3::GROUP_DBTYPE_SERVERQUERY) { 136 | return "ServerQuery"; 137 | } 138 | 139 | return "Unknown"; 140 | } 141 | 142 | /** 143 | * Converts a given permission type ID to a human readable name. 144 | * 145 | * @param integer $type 146 | * @return string 147 | */ 148 | public static function permissionType($type) 149 | { 150 | if ($type == TeamSpeak3::PERM_TYPE_SERVERGROUP) { 151 | return "Server Group"; 152 | } 153 | if ($type == TeamSpeak3::PERM_TYPE_CLIENT) { 154 | return "Client"; 155 | } 156 | if ($type == TeamSpeak3::PERM_TYPE_CHANNEL) { 157 | return "Channel"; 158 | } 159 | if ($type == TeamSpeak3::PERM_TYPE_CHANNELGROUP) { 160 | return "Channel Group"; 161 | } 162 | if ($type == TeamSpeak3::PERM_TYPE_CHANNELCLIENT) { 163 | return "Channel Client"; 164 | } 165 | 166 | return "Unknown"; 167 | } 168 | 169 | /** 170 | * Converts a given permission category value to a human readable name. 171 | * 172 | * @param integer $pcat 173 | * @return string 174 | */ 175 | public static function permissionCategory($pcat) 176 | { 177 | if ($pcat == TeamSpeak3::PERM_CAT_GLOBAL) { 178 | return "Global"; 179 | } 180 | if ($pcat == TeamSpeak3::PERM_CAT_GLOBAL_INFORMATION) { 181 | return "Global / Information"; 182 | } 183 | if ($pcat == TeamSpeak3::PERM_CAT_GLOBAL_SERVER_MGMT) { 184 | return "Global / Virtual Server Management"; 185 | } 186 | if ($pcat == TeamSpeak3::PERM_CAT_GLOBAL_ADM_ACTIONS) { 187 | return "Global / Administration"; 188 | } 189 | if ($pcat == TeamSpeak3::PERM_CAT_GLOBAL_SETTINGS) { 190 | return "Global / Settings"; 191 | } 192 | if ($pcat == TeamSpeak3::PERM_CAT_SERVER) { 193 | return "Virtual Server"; 194 | } 195 | if ($pcat == TeamSpeak3::PERM_CAT_SERVER_INFORMATION) { 196 | return "Virtual Server / Information"; 197 | } 198 | if ($pcat == TeamSpeak3::PERM_CAT_SERVER_ADM_ACTIONS) { 199 | return "Virtual Server / Administration"; 200 | } 201 | if ($pcat == TeamSpeak3::PERM_CAT_SERVER_SETTINGS) { 202 | return "Virtual Server / Settings"; 203 | } 204 | if ($pcat == TeamSpeak3::PERM_CAT_CHANNEL) { 205 | return "Channel"; 206 | } 207 | if ($pcat == TeamSpeak3::PERM_CAT_CHANNEL_INFORMATION) { 208 | return "Channel / Information"; 209 | } 210 | if ($pcat == TeamSpeak3::PERM_CAT_CHANNEL_CREATE) { 211 | return "Channel / Create"; 212 | } 213 | if ($pcat == TeamSpeak3::PERM_CAT_CHANNEL_MODIFY) { 214 | return "Channel / Modify"; 215 | } 216 | if ($pcat == TeamSpeak3::PERM_CAT_CHANNEL_DELETE) { 217 | return "Channel / Delete"; 218 | } 219 | if ($pcat == TeamSpeak3::PERM_CAT_CHANNEL_ACCESS) { 220 | return "Channel / Access"; 221 | } 222 | if ($pcat == TeamSpeak3::PERM_CAT_GROUP) { 223 | return "Group"; 224 | } 225 | if ($pcat == TeamSpeak3::PERM_CAT_GROUP_INFORMATION) { 226 | return "Group / Information"; 227 | } 228 | if ($pcat == TeamSpeak3::PERM_CAT_GROUP_CREATE) { 229 | return "Group / Create"; 230 | } 231 | if ($pcat == TeamSpeak3::PERM_CAT_GROUP_MODIFY) { 232 | return "Group / Modify"; 233 | } 234 | if ($pcat == TeamSpeak3::PERM_CAT_GROUP_DELETE) { 235 | return "Group / Delete"; 236 | } 237 | if ($pcat == TeamSpeak3::PERM_CAT_CLIENT) { 238 | return "Client"; 239 | } 240 | if ($pcat == TeamSpeak3::PERM_CAT_CLIENT_INFORMATION) { 241 | return "Client / Information"; 242 | } 243 | if ($pcat == TeamSpeak3::PERM_CAT_CLIENT_ADM_ACTIONS) { 244 | return "Client / Admin"; 245 | } 246 | if ($pcat == TeamSpeak3::PERM_CAT_CLIENT_BASICS) { 247 | return "Client / Basics"; 248 | } 249 | if ($pcat == TeamSpeak3::PERM_CAT_CLIENT_MODIFY) { 250 | return "Client / Modify"; 251 | } 252 | if ($pcat == TeamSpeak3::PERM_CAT_FILETRANSFER) { 253 | return "File Transfer"; 254 | } 255 | if ($pcat == TeamSpeak3::PERM_CAT_NEEDED_MODIFY_POWER) { 256 | return "Grant"; 257 | } 258 | 259 | return "Unknown"; 260 | } 261 | 262 | /** 263 | * Converts a given log level ID to a human readable name and vice versa. 264 | * 265 | * @param mixed $level 266 | * @return string 267 | */ 268 | public static function logLevel($level) 269 | { 270 | if (is_numeric($level)) { 271 | if ($level == TeamSpeak3::LOGLEVEL_CRITICAL) { 272 | return "CRITICAL"; 273 | } 274 | if ($level == TeamSpeak3::LOGLEVEL_ERROR) { 275 | return "ERROR"; 276 | } 277 | if ($level == TeamSpeak3::LOGLEVEL_DEBUG) { 278 | return "DEBUG"; 279 | } 280 | if ($level == TeamSpeak3::LOGLEVEL_WARNING) { 281 | return "WARNING"; 282 | } 283 | if ($level == TeamSpeak3::LOGLEVEL_INFO) { 284 | return "INFO"; 285 | } 286 | 287 | return "DEVELOP"; 288 | } else { 289 | if (strtoupper($level) == "CRITICAL") { 290 | return TeamSpeak3::LOGLEVEL_CRITICAL; 291 | } 292 | if (strtoupper($level) == "ERROR") { 293 | return TeamSpeak3::LOGLEVEL_ERROR; 294 | } 295 | if (strtoupper($level) == "DEBUG") { 296 | return TeamSpeak3::LOGLEVEL_DEBUG; 297 | } 298 | if (strtoupper($level) == "WARNING") { 299 | return TeamSpeak3::LOGLEVEL_WARNING; 300 | } 301 | if (strtoupper($level) == "INFO") { 302 | return TeamSpeak3::LOGLEVEL_INFO; 303 | } 304 | 305 | return TeamSpeak3::LOGLEVEL_DEVEL; 306 | } 307 | } 308 | 309 | /** 310 | * Converts a specified log entry string into an array containing the data. 311 | * 312 | * @param string $entry 313 | * @return array 314 | */ 315 | public static function logEntry($entry) 316 | { 317 | $parts = explode("|", $entry, 5); 318 | $array = array(); 319 | 320 | if (count($parts) != 5) { 321 | $array["timestamp"] = 0; 322 | $array["level"] = TeamSpeak3::LOGLEVEL_ERROR; 323 | $array["channel"] = "ParamParser"; 324 | $array["server_id"] = ""; 325 | $array["msg"] = StringHelper::factory("convert error (" . trim($entry) . ")"); 326 | $array["msg_plain"] = $entry; 327 | $array["malformed"] = true; 328 | } else { 329 | $array["timestamp"] = strtotime(trim($parts[0])); 330 | $array["level"] = self::logLevel(trim($parts[1])); 331 | $array["channel"] = trim($parts[2]); 332 | $array["server_id"] = trim($parts[3]); 333 | $array["msg"] = StringHelper::factory(trim($parts[4])); 334 | $array["msg_plain"] = $entry; 335 | $array["malformed"] = false; 336 | } 337 | 338 | return $array; 339 | } 340 | 341 | /** 342 | * Converts a given string to a ServerQuery password hash. 343 | * 344 | * @param string $plain 345 | * @return string 346 | */ 347 | public static function password($plain) 348 | { 349 | return base64_encode(sha1($plain, true)); 350 | } 351 | 352 | /** 353 | * Returns a client-like formatted version of the TeamSpeak 3 version string. 354 | * 355 | * @param string $version 356 | * @param string $format 357 | * @return string 358 | */ 359 | public static function version($version, $format = "Y-m-d h:i:s") 360 | { 361 | if (!$version instanceof StringHelper) { 362 | $version = new StringHelper($version); 363 | } 364 | 365 | $buildno = $version->section("[", 1)->filterDigits()->toInt(); 366 | 367 | return ($buildno <= 15001) ? $version : $version->section("[")->append("(" . date($format, $buildno) . ")"); 368 | } 369 | 370 | /** 371 | * Returns a client-like short-formatted version of the TeamSpeak 3 version string. 372 | * 373 | * @param string $version 374 | * @return string 375 | */ 376 | public static function versionShort($version) 377 | { 378 | if (!$version instanceof StringHelper) { 379 | $version = new StringHelper($version); 380 | } 381 | 382 | return $version->section(" ", 0); 383 | } 384 | 385 | /** 386 | * Tries to detect the type of an image by a given string and returns it. 387 | * 388 | * @param string $binary 389 | * @return string 390 | */ 391 | public static function imageMimeType($binary) 392 | { 393 | if (!preg_match( 394 | '/\A(?:(\xff\xd8\xff)|(GIF8[79]a)|(\x89PNG\x0d\x0a)|(BM)|(\x49\x49(\x2a\x00|\x00\x4a))|(FORM.{4}ILBM))/', 395 | $binary, 396 | $matches 397 | ) 398 | ) { 399 | return "application/octet-stream"; 400 | } 401 | 402 | $type = array( 403 | 1 => "image/jpeg", 404 | 2 => "image/gif", 405 | 3 => "image/png", 406 | 4 => "image/x-windows-bmp", 407 | 5 => "image/tiff", 408 | 6 => "image/x-ilbm", 409 | ); 410 | 411 | return $type[count($matches) - 1]; 412 | } 413 | } 414 | -------------------------------------------------------------------------------- /TeamSpeak3/Helper/Profiler.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Helper; 29 | 30 | use TeamSpeak3\Helper\Profiler\Timer; 31 | 32 | /** 33 | * @class Profiler 34 | * @brief Helper class for profiler handling. 35 | */ 36 | class Profiler 37 | { 38 | /** 39 | * Stores various timers for code profiling. 40 | * 41 | * @var array 42 | */ 43 | protected static $timers = array(); 44 | 45 | /** 46 | * Inits a timer. 47 | * 48 | * @param string $name 49 | * @return void 50 | */ 51 | public static function init($name = "default") 52 | { 53 | self::$timers[$name] = new Timer($name); 54 | } 55 | 56 | /** 57 | * Starts a timer. 58 | * 59 | * @param string $name 60 | * @return void 61 | */ 62 | public static function start($name = "default") 63 | { 64 | if (array_key_exists($name, self::$timers)) { 65 | self::$timers[$name]->start(); 66 | } else { 67 | self::$timers[$name] = new Timer($name); 68 | } 69 | } 70 | 71 | /** 72 | * Stops a timer. 73 | * 74 | * @param string $name 75 | * @return void 76 | */ 77 | public static function stop($name = "default") 78 | { 79 | if (!array_key_exists($name, self::$timers)) { 80 | self::init($name); 81 | } 82 | 83 | self::$timers[$name]->stop(); 84 | } 85 | 86 | /** 87 | * Returns a timer. 88 | * 89 | * @param string $name 90 | * @return Timer 91 | */ 92 | public static function get($name = "default") 93 | { 94 | if (!array_key_exists($name, self::$timers)) { 95 | self::init($name); 96 | } 97 | 98 | return self::$timers[$name]; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /TeamSpeak3/Helper/Profiler/Timer.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Helper\Profiler; 29 | 30 | /** 31 | * @class Timer 32 | * @brief Helper class providing profiler timers. 33 | */ 34 | class Timer 35 | { 36 | /** 37 | * Indicates wether the timer is running or not. 38 | * 39 | * @var boolean 40 | */ 41 | protected $running = false; 42 | 43 | /** 44 | * Stores the timestamp when the timer was last started. 45 | * 46 | * @var integer 47 | */ 48 | protected $started = 0; 49 | 50 | /** 51 | * Stores the timer name. 52 | * 53 | * @var string 54 | */ 55 | protected $name = null; 56 | 57 | /** 58 | * Stores various information about the server environment. 59 | * 60 | * @var array 61 | */ 62 | protected $data = array(); 63 | 64 | /** 65 | * The Timer constructor. 66 | * 67 | * @param string $name 68 | * @return Timer 69 | */ 70 | public function __construct($name) 71 | { 72 | $this->name = (string)$name; 73 | 74 | $this->data["runtime"] = 0; 75 | $this->data["realmem"] = 0; 76 | $this->data["emalloc"] = 0; 77 | 78 | $this->start(); 79 | } 80 | 81 | /** 82 | * Starts the timer. 83 | * 84 | * @return void 85 | */ 86 | public function start() 87 | { 88 | if ($this->isRunning()) { 89 | return; 90 | } 91 | 92 | $this->data["realmem_start"] = memory_get_usage(true); 93 | $this->data["emalloc_start"] = memory_get_usage(); 94 | 95 | $this->started = microtime(true); 96 | $this->running = true; 97 | } 98 | 99 | /** 100 | * Stops the timer. 101 | * 102 | * @return void 103 | */ 104 | public function stop() 105 | { 106 | if (!$this->isRunning()) { 107 | return; 108 | } 109 | 110 | $this->data["runtime"] += microtime(true) - $this->started; 111 | $this->data["realmem"] += memory_get_usage(true) - $this->data["realmem_start"]; 112 | $this->data["emalloc"] += memory_get_usage() - $this->data["emalloc_start"]; 113 | 114 | $this->started = 0; 115 | $this->running = false; 116 | } 117 | 118 | /** 119 | * Return the timer runtime. 120 | * 121 | * @return mixed 122 | */ 123 | public function getRuntime() 124 | { 125 | if ($this->isRunning()) { 126 | $this->stop(); 127 | $this->start(); 128 | } 129 | 130 | return $this->data["runtime"]; 131 | } 132 | 133 | /** 134 | * Returns the amount of memory allocated to PHP in bytes. 135 | * 136 | * @param boolean $realmem 137 | * @return integer 138 | */ 139 | public function getMemUsage($realmem = false) 140 | { 141 | if ($this->isRunning()) { 142 | $this->stop(); 143 | $this->start(); 144 | } 145 | 146 | return ($realmem !== false) ? $this->data["realmem"] : $this->data["emalloc"]; 147 | } 148 | 149 | /** 150 | * Returns TRUE if the timer is running. 151 | * 152 | * @return boolean 153 | */ 154 | public function isRunning() 155 | { 156 | return $this->running; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /TeamSpeak3/Helper/Signal.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Helper; 29 | 30 | use TeamSpeak3\Helper\Signal\Handler; 31 | use TeamSpeak3\Ts3Exception; 32 | 33 | /** 34 | * @class Signal 35 | * @brief Helper class for signal slots. 36 | */ 37 | class Signal 38 | { 39 | /** 40 | * Stores the Signal object. 41 | * 42 | * @var Signal 43 | */ 44 | protected static $instance = null; 45 | 46 | /** 47 | * Stores subscribed signals and their slots. 48 | * 49 | * @var array 50 | */ 51 | protected $sigslots = array(); 52 | 53 | /** 54 | * Emits a signal with a given set of parameters. 55 | * 56 | * @param string $signal 57 | * @param mixed $params 58 | * @return mixed 59 | */ 60 | public function emit($signal, $params = null) 61 | { 62 | if (!$this->hasHandlers($signal)) { 63 | return; 64 | } 65 | 66 | if (!is_array($params)) { 67 | $params = func_get_args(); 68 | $params = array_slice($params, 1); 69 | } 70 | 71 | foreach ($this->sigslots[$signal] as $slot) { 72 | $return = $slot->call($params); 73 | } 74 | 75 | return $return; 76 | } 77 | 78 | /** 79 | * Generates a MD5 hash based on a given callback. 80 | * 81 | * @param mixed $callback 82 | * @throws \Teamspeak3\Ts3Exception 83 | * @internal param $string 84 | * @return string 85 | */ 86 | public function getCallbackHash($callback) 87 | { 88 | if (!is_callable($callback, true, $callable_name)) { 89 | throw new Ts3Exception("invalid callback specified"); 90 | } 91 | 92 | return md5($callable_name); 93 | } 94 | 95 | /** 96 | * Subscribes to a signal and returns the signal handler. 97 | * 98 | * @param string $signal 99 | * @param mixed $callback 100 | * @return Handler 101 | */ 102 | public function subscribe($signal, $callback) 103 | { 104 | if (empty($this->sigslots[$signal])) { 105 | $this->sigslots[$signal] = array(); 106 | } 107 | 108 | $index = $this->getCallbackHash($callback); 109 | 110 | if (!array_key_exists($index, $this->sigslots[$signal])) { 111 | $this->sigslots[$signal][$index] = new Handler($signal, $callback); 112 | } 113 | 114 | return $this->sigslots[$signal][$index]; 115 | } 116 | 117 | /** 118 | * Unsubscribes from a signal. 119 | * 120 | * @param string $signal 121 | * @param mixed $callback 122 | * @return void 123 | */ 124 | public function unsubscribe($signal, $callback = null) 125 | { 126 | if (!$this->hasHandlers($signal)) { 127 | return; 128 | } 129 | 130 | if ($callback !== null) { 131 | $index = $this->getCallbackHash($callback); 132 | 133 | if (!array_key_exists($index, $this->sigslots[$signal])) { 134 | return; 135 | } 136 | 137 | unset($this->sigslots[$signal][$index]); 138 | } else { 139 | unset($this->sigslots[$signal]); 140 | } 141 | } 142 | 143 | /** 144 | * Returns all registered signals. 145 | * 146 | * @return array 147 | */ 148 | public function getSignals() 149 | { 150 | return array_keys($this->sigslots); 151 | } 152 | 153 | /** 154 | * Returns TRUE there are slots subscribed for a specified signal. 155 | * 156 | * @param string $signal 157 | * @return boolean 158 | */ 159 | public function hasHandlers($signal) 160 | { 161 | return empty($this->sigslots[$signal]) ? false : true; 162 | } 163 | 164 | /** 165 | * Returns all slots for a specified signal. 166 | * 167 | * @param string $signal 168 | * @return array 169 | */ 170 | public function getHandlers($signal) 171 | { 172 | if (!$this->hasHandlers($signal)) { 173 | return $this->sigslots[$signal]; 174 | } 175 | 176 | return array(); 177 | } 178 | 179 | /** 180 | * Clears all slots for a specified signal. 181 | * 182 | * @param string $signal 183 | * @return void 184 | */ 185 | public function clearHandlers($signal) 186 | { 187 | if (!$this->hasHandlers($signal)) { 188 | unset($this->sigslots[$signal]); 189 | } 190 | } 191 | 192 | /** 193 | * Returns a singleton instance of Signal. 194 | * 195 | * @return Signal 196 | */ 197 | public static function getInstance() 198 | { 199 | if (self::$instance === null) { 200 | self::$instance = new self(); 201 | } 202 | 203 | return self::$instance; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /TeamSpeak3/Helper/Signal/Handler.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Helper\Signal; 29 | 30 | use TeamSpeak3\Ts3Exception; 31 | 32 | /** 33 | * @class Handler 34 | * @brief Helper class providing handler functions for signals. 35 | */ 36 | class Handler 37 | { 38 | /** 39 | * Stores the name of the subscribed signal. 40 | * 41 | * @var string 42 | */ 43 | protected $signal = null; 44 | 45 | /** 46 | * Stores the callback function for the subscribed signal. 47 | * 48 | * @var mixed 49 | */ 50 | protected $callback = null; 51 | 52 | /** 53 | * The Handler constructor. 54 | * 55 | * @param string $signal 56 | * @param mixed $callback 57 | * @throws Ts3Exception 58 | * @return Handler 59 | */ 60 | public function __construct($signal, $callback) 61 | { 62 | $this->signal = (string)$signal; 63 | 64 | if (!is_callable($callback)) { 65 | throw new Ts3Exception("invalid callback specified for signal '" . $signal . "'"); 66 | } 67 | 68 | $this->callback = $callback; 69 | } 70 | 71 | /** 72 | * Invoke the signal handler. 73 | * 74 | * @param array $args 75 | * @return mixed 76 | */ 77 | public function call(array $args = array()) 78 | { 79 | return call_user_func_array($this->callback, $args); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /TeamSpeak3/Helper/Signal/ISignal.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Helper\Signal; 29 | 30 | use TeamSpeak3\Adapter\AbstractAdapter; 31 | use TeamSpeak3\Adapter\ServerQuery\Event; 32 | use TeamSpeak3\Adapter\ServerQuery\Reply; 33 | use TeamSpeak3\Node\Host; 34 | use TeamSpeak3\Ts3Exception; 35 | use TeamSpeak3\Adapter\FileTransfer; 36 | use TeamSpeak3\Node\Server; 37 | 38 | /** 39 | * @class ISignal 40 | * @brief Interface class describing the layout for Signal callbacks. 41 | */ 42 | interface ISignal 43 | { 44 | /** 45 | * Possible callback for 'Connected' signals. 46 | * 47 | * === Examples === 48 | * - Signal::getInstance()->subscribe("serverqueryConnected", array($object, "onConnect")); 49 | * - Signal::getInstance()->subscribe("filetransferConnected", array($object, "onConnect")); 50 | * - Signal::getInstance()->subscribe("blacklistConnected", array($object, "onConnect")); 51 | * - Signal::getInstance()->subscribe("updateConnected", array($object, "onConnect")); 52 | * 53 | * @param AbstractAdapter $adapter 54 | * @return void 55 | */ 56 | public function onConnect(AbstractAdapter $adapter); 57 | 58 | /** 59 | * Possible callback for 'Disconnected' signals. 60 | * 61 | * === Examples === 62 | * - Signal::getInstance()->subscribe("serverqueryDisconnected", array($object, "onDisconnect")); 63 | * - Signal::getInstance()->subscribe("filetransferDisconnected", array($object, "onDisconnect")); 64 | * - Signal::getInstance()->subscribe("blacklistDisconnected", array($object, "onDisconnect")); 65 | * - Signal::getInstance()->subscribe("updateDisconnected", array($object, "onDisconnect")); 66 | * 67 | * @return void 68 | */ 69 | public function onDisconnect(); 70 | 71 | /** 72 | * Possible callback for 'serverqueryCommandStarted' signals. 73 | * 74 | * === Examples === 75 | * - Signal::getInstance()->subscribe("serverqueryCommandStarted", array($object, "onCommandStarted")); 76 | * 77 | * @param string $cmd 78 | * @return void 79 | */ 80 | public function onCommandStarted($cmd); 81 | 82 | /** 83 | * Possible callback for 'serverqueryCommandFinished' signals. 84 | * 85 | * === Examples === 86 | * - Signal::getInstance()->subscribe("serverqueryCommandFinished", array($object, "onCommandFinished")); 87 | * 88 | * @param string $cmd 89 | * @param Reply $reply 90 | * @return void 91 | */ 92 | public function onCommandFinished($cmd, Reply $reply); 93 | 94 | /** 95 | * Possible callback for 'notifyEvent' signals. 96 | * 97 | * === Examples === 98 | * - Signal::getInstance()->subscribe("notifyEvent", array($object, "onEvent")); 99 | * 100 | * @param Event $event 101 | * @param Host $host 102 | * @return void 103 | */ 104 | public function onEvent(Event $event, Host $host); 105 | 106 | /** 107 | * Possible callback for 'notifyError' signals. 108 | * 109 | * === Examples === 110 | * - Signal::getInstance()->subscribe("notifyError", array($object, "onError")); 111 | * 112 | * @param Reply $reply 113 | * @return void 114 | */ 115 | public function onError(Reply $reply); 116 | 117 | /** 118 | * Possible callback for 'notifyServerselected' signals. 119 | * 120 | * === Examples === 121 | * - Signal::getInstance()->subscribe("notifyServerselected", array($object, "onServerselected")); 122 | * 123 | * @param Host $host 124 | * @return void 125 | */ 126 | public function onServerselected(Host $host); 127 | 128 | /** 129 | * Possible callback for 'notifyServercreated' signals. 130 | * 131 | * === Examples === 132 | * - Signal::getInstance()->subscribe("notifyServercreated", array($object, "onServercreated")); 133 | * 134 | * @param Host $host 135 | * @param integer $sid 136 | * @return void 137 | */ 138 | public function onServercreated(Host $host, $sid); 139 | 140 | /** 141 | * Possible callback for 'notifyServerdeleted' signals. 142 | * 143 | * === Examples === 144 | * - Signal::getInstance()->subscribe("notifyServerdeleted", array($object, "onServerdeleted")); 145 | * 146 | * @param Host $host 147 | * @param integer $sid 148 | * @return void 149 | */ 150 | public function onServerdeleted(Host $host, $sid); 151 | 152 | /** 153 | * Possible callback for 'notifyServerstarted' signals. 154 | * 155 | * === Examples === 156 | * - Signal::getInstance()->subscribe("notifyServerstarted", array($object, "onServerstarted")); 157 | * 158 | * @param Host $host 159 | * @param integer $sid 160 | * @return void 161 | */ 162 | public function onServerstarted(Host $host, $sid); 163 | 164 | /** 165 | * Possible callback for 'notifyServerstopped' signals. 166 | * 167 | * === Examples === 168 | * - Signal::getInstance()->subscribe("notifyServerstopped", array($object, "onServerstopped")); 169 | * 170 | * @param Host $host 171 | * @param integer $sid 172 | * @return void 173 | */ 174 | public function onServerstopped(Host $host, $sid); 175 | 176 | /** 177 | * Possible callback for 'notifyServershutdown' signals. 178 | * 179 | * === Examples === 180 | * - Signal::getInstance()->subscribe("notifyServershutdown", array($object, "onServershutdown")); 181 | * 182 | * @param Host $host 183 | * @return void 184 | */ 185 | public function onServershutdown(Host $host); 186 | 187 | /** 188 | * Possible callback for 'notifyLogin' signals. 189 | * 190 | * === Examples === 191 | * - Signal::getInstance()->subscribe("notifyLogin", array($object, "onLogin")); 192 | * 193 | * @param Host $host 194 | * @return void 195 | */ 196 | public function onLogin(Host $host); 197 | 198 | /** 199 | * Possible callback for 'notifyLogout' signals. 200 | * 201 | * === Examples === 202 | * - Signal::getInstance()->subscribe("notifyLogout", array($object, "onLogout")); 203 | * 204 | * @param Host $host 205 | * @return void 206 | */ 207 | public function onLogout(Host $host); 208 | 209 | /** 210 | * Possible callback for 'notifyTokencreated' signals. 211 | * 212 | * === Examples === 213 | * - Signal::getInstance()->subscribe("notifyTokencreated", array($object, "onTokencreated")); 214 | * 215 | * @param Server $server 216 | * @param string $token 217 | * @return void 218 | */ 219 | public function onTokencreated(Server $server, $token); 220 | 221 | /** 222 | * Possible callback for 'filetransferHandshake' signals. 223 | * 224 | * === Examples === 225 | * - Signal::getInstance()->subscribe("filetransferHandshake", array($object, "onFtHandshake")); 226 | * 227 | * @param FileTransfer $adapter 228 | * @return void 229 | */ 230 | public function onFtHandshake(FileTransfer $adapter); 231 | 232 | /** 233 | * Possible callback for 'filetransferUploadStarted' signals. 234 | * 235 | * === Examples === 236 | * - Signal::getInstance()->subscribe("filetransferUploadStarted", array($object, "onFtUploadStarted")); 237 | * 238 | * @param string $ftkey 239 | * @param integer $seek 240 | * @param integer $size 241 | * @return void 242 | */ 243 | public function onFtUploadStarted($ftkey, $seek, $size); 244 | 245 | /** 246 | * Possible callback for 'filetransferUploadProgress' signals. 247 | * 248 | * === Examples === 249 | * - Signal::getInstance()->subscribe("filetransferUploadProgress", array($object, "onFtUploadProgress")); 250 | * 251 | * @param string $ftkey 252 | * @param integer $seek 253 | * @param integer $size 254 | * @return void 255 | */ 256 | public function onFtUploadProgress($ftkey, $seek, $size); 257 | 258 | /** 259 | * Possible callback for 'filetransferUploadFinished' signals. 260 | * 261 | * === Examples === 262 | * - Signal::getInstance()->subscribe("filetransferUploadFinished", array($object, "onFtUploadFinished")); 263 | * 264 | * @param string $ftkey 265 | * @param integer $seek 266 | * @param integer $size 267 | * @return void 268 | */ 269 | public function onFtUploadFinished($ftkey, $seek, $size); 270 | 271 | /** 272 | * Possible callback for 'filetransferDownloadStarted' signals. 273 | * 274 | * === Examples === 275 | * - Signal::getInstance()->subscribe("filetransferDownloadStarted", array($object, "onFtDownloadStarted")); 276 | * 277 | * @param string $ftkey 278 | * @param integer $buff 279 | * @param integer $size 280 | * @return void 281 | */ 282 | public function onFtDownloadStarted($ftkey, $buff, $size); 283 | 284 | /** 285 | * Possible callback for 'filetransferDownloadProgress' signals. 286 | * 287 | * === Examples === 288 | * - Signal::getInstance()->subscribe("filetransferDownloadProgress", array($object, "onFtDownloadProgress")); 289 | * 290 | * @param string $ftkey 291 | * @param integer $buff 292 | * @param integer $size 293 | * @return void 294 | */ 295 | public function onFtDownloadProgress($ftkey, $buff, $size); 296 | 297 | /** 298 | * Possible callback for 'filetransferDownloadFinished' signals. 299 | * 300 | * === Examples === 301 | * - Signal::getInstance()->subscribe("filetransferDownloadFinished", array($object, "onFtDownloadFinished")); 302 | * 303 | * @param string $ftkey 304 | * @param integer $buff 305 | * @param integer $size 306 | * @return void 307 | */ 308 | public function onFtDownloadFinished($ftkey, $buff, $size); 309 | 310 | /** 311 | * Possible callback for 'DataRead' signals. 312 | * 313 | * === Examples === 314 | * - Signal::getInstance()->subscribe("serverqueryDataRead", array($object, "onDebugDataRead")); 315 | * - Signal::getInstance()->subscribe("filetransferDataRead", array($object, "onDebugDataRead")); 316 | * - Signal::getInstance()->subscribe("blacklistDataRead", array($object, "onDebugDataRead")); 317 | * - Signal::getInstance()->subscribe("updateDataRead", array($object, "onDebugDataRead")); 318 | * 319 | * @param string $data 320 | * @return void 321 | */ 322 | public function onDebugDataRead($data); 323 | 324 | /** 325 | * Possible callback for 'DataSend' signals. 326 | * 327 | * === Examples === 328 | * - Signal::getInstance()->subscribe("serverqueryDataSend", array($object, "onDebugDataSend")); 329 | * - Signal::getInstance()->subscribe("filetransferDataSend", array($object, "onDebugDataSend")); 330 | * - Signal::getInstance()->subscribe("blacklistDataSend", array($object, "onDebugDataSend")); 331 | * - Signal::getInstance()->subscribe("updateDataSend", array($object, "onDebugDataSend")); 332 | * 333 | * @param string $data 334 | * @return void 335 | */ 336 | public function onDebugDataSend($data); 337 | 338 | /** 339 | * Possible callback for 'WaitTimeout' signals. 340 | * 341 | * === Examples === 342 | * - Signal::getInstance()->subscribe("serverqueryWaitTimeout", array($object, "onWaitTimeout")); 343 | * - Signal::getInstance()->subscribe("filetransferWaitTimeout", array($object, "onWaitTimeout")); 344 | * - Signal::getInstance()->subscribe("blacklistWaitTimeout", array($object, "onWaitTimeout")); 345 | * - Signal::getInstance()->subscribe("updateWaitTimeout", array($object, "onWaitTimeout")); 346 | * 347 | * @param integer $time 348 | * @param AbstractAdapter $adapter 349 | * @return void 350 | */ 351 | public function onWaitTimeout($time, AbstractAdapter $adapter); 352 | 353 | /** 354 | * Possible callback for 'errorException' signals. 355 | * 356 | * === Examples === 357 | * - Signal::getInstance()->subscribe("errorException", array($object, "onException")); 358 | * 359 | * @param Ts3Exception $e 360 | * @return void 361 | */ 362 | public function onException(Ts3Exception $e); 363 | } 364 | -------------------------------------------------------------------------------- /TeamSpeak3/Helper/Uri.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Helper; 29 | 30 | use TeamSpeak3\Ts3Exception; 31 | 32 | /** 33 | * @class Uri 34 | * @brief Helper class for URI handling. 35 | */ 36 | class Uri 37 | { 38 | /** 39 | * Stores the URI scheme. 40 | * 41 | * @var string 42 | */ 43 | protected $scheme = null; 44 | 45 | /** 46 | * Stores the URI username 47 | * 48 | * @var string 49 | */ 50 | protected $user = null; 51 | 52 | /** 53 | * Stores the URI password. 54 | * 55 | * @var string 56 | */ 57 | protected $pass = null; 58 | 59 | /** 60 | * Stores the URI host. 61 | * 62 | * @var string 63 | */ 64 | protected $host = null; 65 | 66 | /** 67 | * Stores the URI port. 68 | * 69 | * @var string 70 | */ 71 | protected $port = null; 72 | 73 | /** 74 | * Stores the URI path. 75 | * 76 | * @var string 77 | */ 78 | protected $path = null; 79 | 80 | /** 81 | * Stores the URI query string. 82 | * 83 | * @var string 84 | */ 85 | protected $query = null; 86 | 87 | /** 88 | * Stores the URI fragment string. 89 | * 90 | * @var string 91 | */ 92 | protected $fragment = null; 93 | 94 | /** 95 | * Stores grammar rules for validation via regex. 96 | * 97 | * @var array 98 | */ 99 | protected $regex = array(); 100 | 101 | /** 102 | * The Uri constructor. 103 | * 104 | * @param string $uri 105 | * @throws Ts3Exception 106 | * @return Uri 107 | */ 108 | public function __construct($uri) 109 | { 110 | $uri = explode(":", strval($uri), 2); 111 | 112 | $this->scheme = strtolower($uri[0]); 113 | $uriString = isset($uri[1]) ? $uri[1] : ""; 114 | 115 | if (!ctype_alnum($this->scheme)) { 116 | throw new Ts3Exception("invalid URI scheme '" . $this->scheme . "' supplied"); 117 | } 118 | 119 | /* grammar rules for validation */ 120 | $this->regex["alphanum"] = "[^\W_]"; 121 | $this->regex["escaped"] = "(?:%[\da-fA-F]{2})"; 122 | $this->regex["mark"] = "[-_.!~*'()\[\]]"; 123 | $this->regex["reserved"] = "[;\/?:@&=+$,]"; 124 | $this->regex["unreserved"] = "(?:" . $this->regex["alphanum"] . "|" . $this->regex["mark"] . ")"; 125 | $this->regex["segment"] = "(?:(?:" . $this->regex["unreserved"] . "|" . $this->regex["escaped"] . "|[:@&=+$,;])*)"; 126 | $this->regex["path"] = "(?:\/" . $this->regex["segment"] . "?)+"; 127 | $this->regex["uric"] = "(?:" . $this->regex["reserved"] . "|" . $this->regex["unreserved"] . "|" . $this->regex["escaped"] . ")"; 128 | 129 | if (strlen($uriString) > 0) { 130 | $this->parseUri($uriString); 131 | } 132 | 133 | if (!$this->isValid()) { 134 | throw new Ts3Exception("invalid URI supplied"); 135 | } 136 | } 137 | 138 | /** 139 | * Parses the scheme-specific portion of the URI and place its parts into instance variables. 140 | * 141 | * @param string $uriString 142 | * @throws \Teamspeak3\Ts3Exception 143 | * @return void 144 | */ 145 | protected function parseUri($uriString = '') 146 | { 147 | $status = @preg_match("~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~", $uriString, $matches); 148 | 149 | if ($status === false) { 150 | throw new Ts3Exception("URI scheme-specific decomposition failed"); 151 | } 152 | 153 | if (!$status) { 154 | return; 155 | } 156 | 157 | $this->path = (isset($matches[4])) ? $matches[4] : ''; 158 | $this->query = (isset($matches[6])) ? $matches[6] : ''; 159 | $this->fragment = (isset($matches[8])) ? $matches[8] : ''; 160 | 161 | $status = @preg_match( 162 | "~^(([^:@]*)(:([^@]*))?@)?([^:]+)(:(.*))?$~", 163 | (isset($matches[3])) ? $matches[3] : "", 164 | $matches 165 | ); 166 | 167 | if ($status === false) { 168 | throw new Ts3Exception("URI scheme-specific authority decomposition failed"); 169 | } 170 | 171 | if (!$status) { 172 | return; 173 | } 174 | 175 | $this->user = isset($matches[2]) ? $matches[2] : ""; 176 | $this->pass = isset($matches[4]) ? $matches[4] : ""; 177 | $this->host = isset($matches[5]) ? $matches[5] : ""; 178 | $this->port = isset($matches[7]) ? $matches[7] : ""; 179 | } 180 | 181 | /** 182 | * Validate the current URI from the instance variables. 183 | * 184 | * @return boolean 185 | */ 186 | public function isValid() 187 | { 188 | return ($this->checkUser() && $this->checkPass() && $this->checkHost() && $this->checkPort( 189 | ) && $this->checkPath() && $this->checkQuery() && $this->checkFragment()); 190 | } 191 | 192 | /** 193 | * Returns TRUE if a given URI is valid. 194 | * 195 | * @param string $uri 196 | * @return boolean 197 | */ 198 | public static function check($uri) 199 | { 200 | try { 201 | $uri = new self(strval($uri)); 202 | } catch (Ts3Exception $e) { 203 | return false; 204 | } 205 | 206 | return $uri->valid(); 207 | } 208 | 209 | /** 210 | * Returns TRUE if the URI has a scheme. 211 | * 212 | * @return boolean 213 | */ 214 | public function hasScheme() 215 | { 216 | return strlen($this->scheme) ? true : false; 217 | } 218 | 219 | /** 220 | * Returns the scheme. 221 | * 222 | * @param mixed $default 223 | * @return StringHelper 224 | */ 225 | public function getScheme($default = null) 226 | { 227 | return ($this->hasScheme()) ? new StringHelper($this->scheme) : $default; 228 | } 229 | 230 | /** 231 | * Returns TRUE if the username is valid. 232 | * 233 | * @param string $username 234 | * @throws Ts3Exception 235 | * @return boolean 236 | */ 237 | public function checkUser($username = null) 238 | { 239 | if ($username === null) { 240 | $username = $this->user; 241 | } 242 | 243 | if (strlen($username) == 0) { 244 | return true; 245 | } 246 | 247 | $pattern = "/^(" . $this->regex["alphanum"] . "|" . $this->regex["mark"] . "|" . $this->regex["escaped"] . "|[;:&=+$,])+$/"; 248 | $status = @preg_match($pattern, $username); 249 | 250 | if ($status === false) { 251 | throw new Ts3Exception("URI username validation failed"); 252 | } 253 | 254 | return ($status == 1); 255 | } 256 | 257 | /** 258 | * Returns TRUE if the URI has a username. 259 | * 260 | * @return boolean 261 | */ 262 | public function hasUser() 263 | { 264 | return strlen($this->user) ? true : false; 265 | } 266 | 267 | /** 268 | * Returns the username. 269 | * 270 | * @param mixed $default 271 | * @return StringHelper 272 | */ 273 | public function getUser($default = null) 274 | { 275 | return ($this->hasUser()) ? new StringHelper($this->user) : $default; 276 | } 277 | 278 | /** 279 | * Returns TRUE if the password is valid. 280 | * 281 | * @param string $password 282 | * @throws Ts3Exception 283 | * @return boolean 284 | */ 285 | public function checkPass($password = null) 286 | { 287 | if ($password === null) { 288 | $password = $this->pass; 289 | } 290 | 291 | if (strlen($password) == 0) { 292 | return true; 293 | } 294 | 295 | $pattern = "/^(" . $this->regex["alphanum"] . "|" . $this->regex["mark"] . "|" . $this->regex["escaped"] . "|[;:&=+$,])+$/"; 296 | $status = @preg_match($pattern, $password); 297 | 298 | if ($status === false) { 299 | throw new Ts3Exception("URI password validation failed"); 300 | } 301 | 302 | return ($status == 1); 303 | } 304 | 305 | /** 306 | * Returns TRUE if the URI has a password. 307 | * 308 | * @return boolean 309 | */ 310 | public function hasPass() 311 | { 312 | return strlen($this->pass) ? true : false; 313 | } 314 | 315 | /** 316 | * Returns the password. 317 | * 318 | * @param mixed $default 319 | * @return StringHelper 320 | */ 321 | public function getPass($default = null) 322 | { 323 | return ($this->hasPass()) ? new StringHelper($this->pass) : $default; 324 | } 325 | 326 | /** 327 | * Returns TRUE if the host is valid. 328 | * 329 | * @param string $host 330 | * @return boolean 331 | */ 332 | public function checkHost($host = null) 333 | { 334 | if ($host === null) { 335 | $host = $this->host; 336 | } 337 | 338 | return true; 339 | } 340 | 341 | /** 342 | * Returns TRUE if the URI has a host. 343 | * 344 | * @return boolean 345 | */ 346 | public function hasHost() 347 | { 348 | return strlen($this->host) ? true : false; 349 | } 350 | 351 | /** 352 | * Returns the host. 353 | * 354 | * @param mixed $default 355 | * @return StringHelper 356 | */ 357 | public function getHost($default = null) 358 | { 359 | return ($this->hasHost()) ? new StringHelper($this->host) : $default; 360 | } 361 | 362 | /** 363 | * Returns TRUE if the port is valid. 364 | * 365 | * @param integer $port 366 | * @return boolean 367 | */ 368 | public function checkPort($port = null) 369 | { 370 | if ($port === null) { 371 | $port = $this->port; 372 | } 373 | 374 | return true; 375 | } 376 | 377 | /** 378 | * Returns TRUE if the URI has a port. 379 | * 380 | * @return boolean 381 | */ 382 | public function hasPort() 383 | { 384 | return strlen($this->port) ? true : false; 385 | } 386 | 387 | /** 388 | * Returns the port. 389 | * 390 | * @param mixed $default 391 | * @return integer 392 | */ 393 | public function getPort($default = null) 394 | { 395 | return ($this->hasPort()) ? intval($this->port) : $default; 396 | } 397 | 398 | /** 399 | * Returns TRUE if the path is valid. 400 | * 401 | * @param string $path 402 | * @throws Ts3Exception 403 | * @return boolean 404 | */ 405 | public function checkPath($path = null) 406 | { 407 | if ($path === null) { 408 | $path = $this->path; 409 | } 410 | 411 | if (strlen($path) == 0) { 412 | return true; 413 | } 414 | 415 | $pattern = "/^" . $this->regex["path"] . "$/"; 416 | $status = @preg_match($pattern, $path); 417 | 418 | if ($status === false) { 419 | throw new Ts3Exception("URI path validation failed"); 420 | } 421 | 422 | return ($status == 1); 423 | } 424 | 425 | /** 426 | * Returns TRUE if the URI has a path. 427 | * 428 | * @return boolean 429 | */ 430 | public function hasPath() 431 | { 432 | return strlen($this->path) ? true : false; 433 | } 434 | 435 | /** 436 | * Returns the path. 437 | * 438 | * @param mixed $default 439 | * @return StringHelper 440 | */ 441 | public function getPath($default = null) 442 | { 443 | return ($this->hasPath()) ? new StringHelper($this->path) : $default; 444 | } 445 | 446 | /** 447 | * Returns TRUE if the query string is valid. 448 | * 449 | * @param string $query 450 | * @throws Ts3Exception 451 | * @return boolean 452 | */ 453 | public function checkQuery($query = null) 454 | { 455 | if ($query === null) { 456 | $query = $this->query; 457 | } 458 | 459 | if (strlen($query) == 0) { 460 | return true; 461 | } 462 | 463 | $pattern = "/^" . $this->regex["uric"] . "*$/"; 464 | $status = @preg_match($pattern, $query); 465 | 466 | if ($status === false) { 467 | throw new Ts3Exception("URI query string validation failed"); 468 | } 469 | 470 | return ($status == 1); 471 | } 472 | 473 | /** 474 | * Returns TRUE if the URI has a query string. 475 | * 476 | * @return boolean 477 | */ 478 | public function hasQuery() 479 | { 480 | return strlen($this->query) ? true : false; 481 | } 482 | 483 | /** 484 | * Returns an array containing the query string elements. 485 | * 486 | * @param mixed $default 487 | * @return array 488 | */ 489 | public function getQuery($default = array()) 490 | { 491 | if (!$this->hasQuery()) { 492 | return $default; 493 | } 494 | 495 | parse_str($this->query, $queryArray); 496 | 497 | return $queryArray; 498 | } 499 | 500 | /** 501 | * Returns TRUE if the URI has a query variable. 502 | * 503 | * @param $key 504 | * @return boolean 505 | */ 506 | public function hasQueryVar($key) 507 | { 508 | if (!$this->hasQuery()) { 509 | return false; 510 | } 511 | 512 | parse_str($this->query, $queryArray); 513 | 514 | return array_key_exists($key, $queryArray) ? true : false; 515 | } 516 | 517 | /** 518 | * Returns a single variable from the query string. 519 | * 520 | * @param string $key 521 | * @param mixed $default 522 | * @return mixed 523 | */ 524 | public function getQueryVar($key, $default = null) 525 | { 526 | if (!$this->hasQuery()) { 527 | return $default; 528 | } 529 | 530 | parse_str($this->query, $queryArray); 531 | 532 | if (array_key_exists($key, $queryArray)) { 533 | $val = $queryArray[$key]; 534 | 535 | if (ctype_digit($val)) { 536 | return intval($val); 537 | } elseif (is_string($val)) { 538 | return new StringHelper($val); 539 | } else { 540 | return $val; 541 | } 542 | } 543 | 544 | return $default; 545 | } 546 | 547 | /** 548 | * Returns TRUE if the fragment string is valid. 549 | * 550 | * @param string $fragment 551 | * @throws Ts3Exception 552 | * @return boolean 553 | */ 554 | public function checkFragment($fragment = null) 555 | { 556 | if ($fragment === null) { 557 | $fragment = $this->fragment; 558 | } 559 | 560 | if (strlen($fragment) == 0) { 561 | return true; 562 | } 563 | 564 | $pattern = "/^" . $this->regex["uric"] . "*$/"; 565 | $status = @preg_match($pattern, $fragment); 566 | 567 | if ($status === false) { 568 | throw new Ts3Exception("URI fragment validation failed"); 569 | } 570 | 571 | return ($status == 1); 572 | } 573 | 574 | /** 575 | * Returns TRUE if the URI has a fragment string. 576 | * 577 | * @return boolean 578 | */ 579 | public function hasFragment() 580 | { 581 | return strlen($this->fragment) ? true : false; 582 | } 583 | 584 | /** 585 | * Returns the fragment. 586 | * 587 | * @param mixed $default 588 | * @return StringHelper 589 | */ 590 | public function getFragment($default = null) 591 | { 592 | return ($this->hasFragment()) ? new StringHelper($this->fragment) : $default; 593 | } 594 | 595 | /** 596 | * Returns a specified instance parameter from the $_REQUEST array. 597 | * 598 | * @param string $key 599 | * @param mixed $default 600 | * @return mixed 601 | */ 602 | public static function getUserParam($key, $default = null) 603 | { 604 | return (array_key_exists($key, $_REQUEST) && !empty($_REQUEST[$key])) ? self::stripslashesRecursive( 605 | $_REQUEST[$key] 606 | ) : $default; 607 | } 608 | 609 | /** 610 | * Returns a specified environment parameter from the $_SERVER array. 611 | * 612 | * @param string $key 613 | * @param mixed $default 614 | * @return mixed 615 | */ 616 | public static function getHostParam($key, $default = null) 617 | { 618 | return (array_key_exists($key, $_SERVER) && !empty($_SERVER[$key])) ? $_SERVER[$key] : $default; 619 | } 620 | 621 | /** 622 | * Returns a specified session parameter from the $_SESSION array. 623 | * 624 | * @param string $key 625 | * @param mixed $default 626 | * @return mixed 627 | */ 628 | public static function getSessParam($key, $default = null) 629 | { 630 | return (array_key_exists($key, $_SESSION) && !empty($_SESSION[$key])) ? $_SESSION[$key] : $default; 631 | } 632 | 633 | /** 634 | * Returns an array containing the three main parts of a FQDN (Fully Qualified Domain Name), including the 635 | * top-level domain, the second-level domains or hostname and the third-level domain. 636 | * 637 | * @param string $hostname 638 | * @return array 639 | */ 640 | public static function getFQDNParts($hostname) 641 | { 642 | if (!preg_match( 643 | "/^([a-z0-9][a-z0-9-]{0,62}\.)*([a-z0-9][a-z0-9-]{0,62}\.)+([a-z]{2,6})$/i", 644 | $hostname, 645 | $matches 646 | ) 647 | ) { 648 | return array(); 649 | } 650 | 651 | $parts["tld"] = $matches[3]; 652 | $parts["2nd"] = $matches[2]; 653 | $parts["3rd"] = $matches[1]; 654 | 655 | return $parts; 656 | } 657 | 658 | /** 659 | * Returns the applications host address. 660 | * 661 | * @return StringHelper 662 | */ 663 | public static function getHostUri() 664 | { 665 | $sheme = (self::getHostParam("HTTPS") == "on") ? "https" : "http"; 666 | 667 | $serverName = new StringHelper(self::getHostParam("HTTP_HOST")); 668 | $serverPort = self::getHostParam("SERVER_PORT"); 669 | $serverPort = ($serverPort != 80 && $serverPort != 443) ? ":" . $serverPort : ""; 670 | 671 | if ($serverName->endsWith($serverPort)) { 672 | $serverName = $serverName->replace($serverPort, ""); 673 | } 674 | 675 | return new StringHelper($sheme . "://" . $serverName . $serverPort); 676 | } 677 | 678 | /** 679 | * Returns the applications base address. 680 | * 681 | * @return string 682 | */ 683 | public static function getBaseUri() 684 | { 685 | $scriptPath = new StringHelper(dirname(self::getHostParam("SCRIPT_NAME"))); 686 | 687 | return self::getHostUri()->append(($scriptPath == DIRECTORY_SEPARATOR ? "" : $scriptPath) . "/"); 688 | } 689 | 690 | /** 691 | * Strips slashes from each element of an array using stripslashes(). 692 | * 693 | * @param mixed $var 694 | * @return mixed 695 | */ 696 | protected static function stripslashesRecursive($var) 697 | { 698 | if (!is_array($var)) { 699 | return stripslashes(strval($var)); 700 | } 701 | 702 | foreach ($var as $key => $val) { 703 | $var[$key] = (is_array($val)) ? self::stripslashesRecursive($val) : stripslashes(strval($val)); 704 | } 705 | 706 | return $var; 707 | } 708 | } 709 | -------------------------------------------------------------------------------- /TeamSpeak3/Node/AbstractNode.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Node; 29 | 30 | use \RecursiveIterator; 31 | use \ArrayAccess; 32 | use \Countable; 33 | use TeamSpeak3\Adapter\ServerQuery\Reply; 34 | use TeamSpeak3\Adapter\ServerQuery; 35 | use TeamSpeak3\Helper\Convert; 36 | use TeamSpeak3\Helper\StringHelper; 37 | use TeamSpeak3\Ts3Exception; 38 | use TeamSpeak3\Viewer\IViewer; 39 | 40 | /** 41 | * @class AbstractNode 42 | * @brief Abstract class describing a TeamSpeak 3 node and all it's parameters. 43 | */ 44 | abstract class AbstractNode implements RecursiveIterator, ArrayAccess, Countable 45 | { 46 | /** 47 | * @ignore 48 | */ 49 | protected $parent = null; 50 | 51 | /** 52 | * @ignore 53 | */ 54 | protected $server = null; 55 | 56 | /** 57 | * @ignore 58 | */ 59 | protected $nodeId = 0x00; 60 | 61 | /** 62 | * @ignore 63 | */ 64 | protected $nodeList = null; 65 | 66 | /** 67 | * @ignore 68 | */ 69 | protected $nodeInfo = array(); 70 | 71 | /** 72 | * @ignore 73 | */ 74 | protected $storage = array(); 75 | 76 | /** 77 | * Sends a prepared command to the server and returns the result. 78 | * 79 | * @param string $cmd 80 | * @param boolean $throw 81 | * @return Reply 82 | */ 83 | public function request($cmd, $throw = true) 84 | { 85 | return $this->getParent()->request($cmd, $throw); 86 | } 87 | 88 | /** 89 | * Uses given parameters and returns a prepared ServerQuery command. 90 | * 91 | * @param string $cmd 92 | * @param array $params 93 | * @return StringHelper 94 | */ 95 | public function prepare($cmd, array $params = array()) 96 | { 97 | return $this->getParent()->prepare($cmd, $params); 98 | } 99 | 100 | /** 101 | * Prepares and executes a ServerQuery command and returns the result. 102 | * 103 | * @param string $cmd 104 | * @param array $params 105 | * @return Reply 106 | */ 107 | public function execute($cmd, array $params = array()) 108 | { 109 | return $this->request($this->prepare($cmd, $params)); 110 | } 111 | 112 | /** 113 | * Returns the parent object of the current node. 114 | * 115 | * @return ServerQuery 116 | * @return AbstractNode 117 | */ 118 | public function getParent() 119 | { 120 | return $this->parent; 121 | } 122 | 123 | /** 124 | * Returns the primary ID of the current node. 125 | * 126 | * @return integer 127 | */ 128 | public function getId() 129 | { 130 | return $this->nodeId; 131 | } 132 | 133 | /** 134 | * Returns TRUE if the node icon has a local source. 135 | * 136 | * @param string $key 137 | * @return boolean 138 | */ 139 | public function iconIsLocal($key) 140 | { 141 | return ($this[$key] > 0 && $this[$key] < 1000) ? true : false; 142 | } 143 | 144 | /** 145 | * Returns the internal path of the node icon. 146 | * 147 | * @param string $key 148 | * @return StringHelper 149 | */ 150 | public function iconGetName($key) 151 | { 152 | $iconid = ($this[$key] < 0) ? (pow(2, 32)) - ($this[$key] * -1) : $this[$key]; 153 | 154 | return new StringHelper("/icon_" . $iconid); 155 | } 156 | 157 | /** 158 | * Returns a possible classname for the node which can be used as a HTML property. 159 | * 160 | * @param string $prefix 161 | * @return string 162 | */ 163 | public function getClass($prefix = "ts3_") 164 | { 165 | if ($this instanceof Channel && $this->isSpacer()) { 166 | return $prefix . "spacer"; 167 | } elseif ($this instanceof Client && $this["client_type"]) { 168 | return $prefix . "query"; 169 | } 170 | 171 | return $prefix . StringHelper::factory(get_class($this))->toLower(); 172 | } 173 | 174 | /** 175 | * Returns a unique identifier for the node which can be used as a HTML property. 176 | * 177 | * @return string 178 | */ 179 | abstract public function getUniqueId(); 180 | 181 | /** 182 | * Returns the name of a possible icon to display the node object. 183 | * 184 | * @return string 185 | */ 186 | abstract public function getIcon(); 187 | 188 | /** 189 | * Returns a symbol representing the node. 190 | * 191 | * @return string 192 | */ 193 | abstract public function getSymbol(); 194 | 195 | /** 196 | * Returns the HTML code to display a TeamSpeak 3 viewer. 197 | * 198 | * @param IViewer $viewer 199 | * @return string 200 | */ 201 | public function getViewer(IViewer $viewer) 202 | { 203 | $html = $viewer->fetchObject($this); 204 | 205 | $iterator = new \RecursiveIteratorIterator($this, \RecursiveIteratorIterator::SELF_FIRST); 206 | 207 | foreach ($iterator as $node) { 208 | $siblings = array(); 209 | 210 | for ($level = 0; $level < $iterator->getDepth(); $level++) { 211 | $siblings[] = ($iterator->getSubIterator($level)->hasNext()) ? 1 : 0; 212 | } 213 | 214 | $siblings[] = (!$iterator->getSubIterator($level)->hasNext()) ? 1 : 0; 215 | 216 | $html .= $viewer->fetchObject($node, $siblings); 217 | } 218 | 219 | return $html; 220 | } 221 | 222 | /** 223 | * Filters given node list array using specified filter rules. 224 | * 225 | * @param array $nodes 226 | * @param array $rules 227 | * @return array 228 | */ 229 | protected function filterList(array $nodes = array(), array $rules = array()) 230 | { 231 | if (!empty($rules)) { 232 | foreach ($nodes as $node) { 233 | if (!$node instanceof AbstractNode) { 234 | continue; 235 | } 236 | 237 | $props = $node->getInfo(false); 238 | $props = array_intersect_key($props, $rules); 239 | $match = true; 240 | 241 | foreach ($props as $key => $val) { 242 | if ($val instanceof StringHelper) { 243 | $match = $val->contains($rules[$key], true); 244 | } else { 245 | $match = $val == $rules[$key]; 246 | } 247 | 248 | if ($match === false) { 249 | unset($nodes[$node->getId()]); 250 | } 251 | } 252 | } 253 | } 254 | 255 | return $nodes; 256 | } 257 | 258 | /** 259 | * Returns all information available on this node. If $convert is enabled, some property 260 | * values will be converted to human-readable values. 261 | * 262 | * @param boolean $extend 263 | * @param boolean $convert 264 | * @return array 265 | */ 266 | public function getInfo($extend = true, $convert = false) 267 | { 268 | if ($extend) { 269 | $this->fetchNodeInfo(); 270 | } 271 | 272 | if ($convert) { 273 | $info = $this->nodeInfo; 274 | 275 | foreach ($info as $key => $val) { 276 | $key = StringHelper::factory($key); 277 | 278 | if ($key->contains("_bytes_")) { 279 | $info[$key->toString()] = Convert::bytes($val); 280 | } elseif ($key->contains("_bandwidth_")) { 281 | $info[$key->toString()] = Convert::bytes($val) . "/s"; 282 | } elseif ($key->contains("_packets_")) { 283 | $info[$key->toString()] = number_format($val, null, null, "."); 284 | } elseif ($key->contains("_packetloss_")) { 285 | $info[$key->toString()] = sprintf("%01.2f", floatval($val->toString()) * 100) . "%"; 286 | } elseif ($key->endsWith("_uptime")) { 287 | $info[$key->toString()] = Convert::seconds($val); 288 | } elseif ($key->endsWith("_version")) { 289 | $info[$key->toString()] = Convert::version($val); 290 | } elseif ($key->endsWith("_icon_id")) { 291 | $info[$key->toString()] = $this->iconGetName($key)->filterDigits(); 292 | } 293 | } 294 | 295 | return $info; 296 | } 297 | 298 | return $this->nodeInfo; 299 | } 300 | 301 | /** 302 | * Returns the specified property or a pre-defined default value from the node info array. 303 | * 304 | * @param string $property 305 | * @param mixed $default 306 | * @return mixed 307 | */ 308 | public function getProperty($property, $default = null) 309 | { 310 | if (!$this->offsetExists($property)) { 311 | $this->fetchNodeInfo(); 312 | } 313 | 314 | if (!$this->offsetExists($property)) { 315 | return $default; 316 | } 317 | 318 | return $this->nodeInfo[(string)$property]; 319 | } 320 | 321 | /** 322 | * Returns a string representation of this node. 323 | * 324 | * @return string 325 | */ 326 | public function __toString() 327 | { 328 | return get_class($this); 329 | } 330 | 331 | /** 332 | * Returns a string representation of this node. 333 | * 334 | * @return string 335 | */ 336 | public function toString() 337 | { 338 | return $this->__toString(); 339 | } 340 | 341 | /** 342 | * Returns an assoc array filled with current node info properties. 343 | * 344 | * @return array 345 | */ 346 | public function toArray() 347 | { 348 | return $this->nodeList; 349 | } 350 | 351 | /** 352 | * Called whenever we're using an unknown method. 353 | * 354 | * @param string $name 355 | * @param array $args 356 | * @throws Ts3Exception 357 | * @return mixed 358 | */ 359 | public function __call($name, array $args) 360 | { 361 | if ($this->getParent() instanceof AbstractNode) { 362 | return call_user_func_array(array($this->getParent(), $name), $args); 363 | } 364 | 365 | throw new Ts3Exception("node method '" . $name . "()' does not exist"); 366 | } 367 | 368 | /** 369 | * Writes data to the internal storage array. 370 | * 371 | * @param string $key 372 | * @param mixed $val 373 | * @return void 374 | */ 375 | protected function setStorage($key, $val) 376 | { 377 | $this->storage[$key] = $val; 378 | } 379 | 380 | /** 381 | * Returns data from the internal storage array. 382 | * 383 | * @param string $key 384 | * @param mixed $default 385 | * @return mixed 386 | */ 387 | protected function getStorage($key, $default = null) 388 | { 389 | return (array_key_exists( 390 | $key, 391 | $this->storage 392 | ) && !empty($this->storage[$key])) ? $this->storage[$key] : $default; 393 | } 394 | 395 | /** 396 | * Deletes data from the internal storage array. 397 | * 398 | * @param string $key 399 | * @return void 400 | */ 401 | protected function delStorage($key) 402 | { 403 | unset($this->storage[$key]); 404 | } 405 | 406 | /** 407 | * Commit pending data. 408 | * 409 | * @return array 410 | */ 411 | public function __sleep() 412 | { 413 | return array("parent", "storage", "nodeId"); 414 | } 415 | 416 | /** 417 | * @ignore 418 | */ 419 | protected function fetchNodeList() 420 | { 421 | $this->nodeList = array(); 422 | } 423 | 424 | /** 425 | * @ignore 426 | */ 427 | protected function fetchNodeInfo() 428 | { 429 | return; 430 | } 431 | 432 | /** 433 | * @ignore 434 | */ 435 | protected function resetNodeInfo() 436 | { 437 | $this->nodeInfo = array(); 438 | } 439 | 440 | /** 441 | * @ignore 442 | */ 443 | protected function verifyNodeList() 444 | { 445 | if ($this->nodeList === null) { 446 | $this->fetchNodeList(); 447 | } 448 | } 449 | 450 | /** 451 | * @ignore 452 | */ 453 | protected function resetNodeList() 454 | { 455 | $this->nodeList = null; 456 | } 457 | 458 | /** 459 | * @ignore 460 | */ 461 | public function count() 462 | { 463 | $this->verifyNodeList(); 464 | 465 | return count($this->nodeList); 466 | } 467 | 468 | /** 469 | * @ignore 470 | */ 471 | public function current() 472 | { 473 | $this->verifyNodeList(); 474 | 475 | return current($this->nodeList); 476 | } 477 | 478 | /** 479 | * @ignore 480 | */ 481 | public function getChildren() 482 | { 483 | $this->verifyNodeList(); 484 | 485 | return $this->current(); 486 | } 487 | 488 | /** 489 | * @ignore 490 | */ 491 | public function hasChildren() 492 | { 493 | $this->verifyNodeList(); 494 | 495 | return $this->current()->count() > 0; 496 | } 497 | 498 | /** 499 | * @ignore 500 | */ 501 | public function hasNext() 502 | { 503 | $this->verifyNodeList(); 504 | 505 | return $this->key() + 1 < $this->count(); 506 | } 507 | 508 | /** 509 | * @ignore 510 | */ 511 | public function key() 512 | { 513 | $this->verifyNodeList(); 514 | 515 | return key($this->nodeList); 516 | } 517 | 518 | /** 519 | * @ignore 520 | */ 521 | public function valid() 522 | { 523 | $this->verifyNodeList(); 524 | 525 | return $this->key() !== null; 526 | } 527 | 528 | /** 529 | * @ignore 530 | */ 531 | public function next() 532 | { 533 | $this->verifyNodeList(); 534 | 535 | return next($this->nodeList); 536 | } 537 | 538 | /** 539 | * @ignore 540 | */ 541 | public function rewind() 542 | { 543 | $this->verifyNodeList(); 544 | 545 | return reset($this->nodeList); 546 | } 547 | 548 | /** 549 | * @ignore 550 | */ 551 | public function offsetExists($offset) 552 | { 553 | return array_key_exists((string)$offset, $this->nodeInfo) ? true : false; 554 | } 555 | 556 | /** 557 | * @ignore 558 | */ 559 | public function offsetGet($offset) 560 | { 561 | if (!$this->offsetExists($offset)) { 562 | $this->fetchNodeInfo(); 563 | } 564 | 565 | if (!$this->offsetExists($offset)) { 566 | throw new Ts3Exception("invalid parameter", 0x602); 567 | } 568 | 569 | return $this->nodeInfo[(string)$offset]; 570 | } 571 | 572 | /** 573 | * @ignore 574 | */ 575 | public function offsetSet($offset, $value) 576 | { 577 | if (method_exists($this, "modify")) { 578 | return $this->modify(array((string)$offset => $value)); 579 | } 580 | 581 | throw new Ts3Exception("node '" . get_class($this) . "' is read only"); 582 | } 583 | 584 | /** 585 | * @ignore 586 | */ 587 | public function offsetUnset($offset) 588 | { 589 | unset($this->nodeInfo[(string)$offset]); 590 | } 591 | 592 | /** 593 | * @ignore 594 | */ 595 | public function __get($offset) 596 | { 597 | return $this->offsetGet($offset); 598 | } 599 | 600 | /** 601 | * @ignore 602 | */ 603 | public function __set($offset, $value) 604 | { 605 | $this->offsetSet($offset, $value); 606 | } 607 | } 608 | -------------------------------------------------------------------------------- /TeamSpeak3/Node/Channel.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Node; 29 | 30 | use TeamSpeak3\TeamSpeak3; 31 | 32 | /** 33 | * @class Channel 34 | * @brief Class describing a TeamSpeak 3 channel and all it's parameters. 35 | */ 36 | class Channel extends AbstractNode 37 | { 38 | /** 39 | * The Channel constructor. 40 | * 41 | * @param Server $server 42 | * @param array $info 43 | * @param string $index 44 | * @throws TeamSpeak3_Adapter_ServerQuery_Exception 45 | * @return Channel 46 | */ 47 | public function __construct(Server $server, array $info, $index = "cid") 48 | { 49 | $this->parent = $server; 50 | $this->nodeInfo = $info; 51 | 52 | if (!array_key_exists($index, $this->nodeInfo)) { 53 | throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); 54 | } 55 | 56 | $this->nodeId = $this->nodeInfo[$index]; 57 | } 58 | 59 | /** 60 | * Returns an array filled with Channel objects. 61 | * 62 | * @param array $filter 63 | * @return array 64 | */ 65 | public function subChannelList(array $filter = array()) 66 | { 67 | $channels = array(); 68 | 69 | foreach ($this->getParent()->channelList() as $channel) { 70 | if ($channel["pid"] == $this->getId()) { 71 | $channels[$channel->getId()] = $channel; 72 | } 73 | } 74 | 75 | return $this->filterList($channels, $filter); 76 | } 77 | 78 | /** 79 | * Returns the Channel object matching the given ID. 80 | * 81 | * @param integer $cid 82 | * @throws TeamSpeak3_Adapter_ServerQuery_Exception 83 | * @return Channel 84 | */ 85 | public function subChannelGetById($cid) 86 | { 87 | if (!array_key_exists((string)$cid, $this->subChannelList())) { 88 | throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); 89 | } 90 | 91 | return $this->channelList[(string)$cid]; 92 | } 93 | 94 | /** 95 | * Returns the Channel object matching the given name. 96 | * 97 | * @param integer $name 98 | * @throws TeamSpeak3_Adapter_ServerQuery_Exception 99 | * @return Channel 100 | */ 101 | public function subChannelGetByName($name) 102 | { 103 | foreach ($this->subChannelList() as $channel) { 104 | if ($channel["channel_name"] == $name) { 105 | return $channel; 106 | } 107 | } 108 | 109 | throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); 110 | } 111 | 112 | /** 113 | * Returns an array filled with Client objects. 114 | * 115 | * @param array $filter 116 | * @return array 117 | */ 118 | public function clientList(array $filter = array()) 119 | { 120 | $clients = array(); 121 | 122 | foreach ($this->getParent()->clientList() as $client) { 123 | if ($client["cid"] == $this->getId()) { 124 | $clients[$client->getId()] = $client; 125 | } 126 | } 127 | 128 | return $this->filterList($clients, $filter); 129 | } 130 | 131 | /** 132 | * Returns the Client object matching the given ID. 133 | * 134 | * @param integer $clid 135 | * @throws TeamSpeak3_Adapter_ServerQuery_Exception 136 | * @return Client 137 | */ 138 | public function clientGetById($clid) 139 | { 140 | if (!array_key_exists($clid, $this->clientList())) { 141 | throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); 142 | } 143 | 144 | return $this->clientList[intval($clid)]; 145 | } 146 | 147 | /** 148 | * Returns the Client object matching the given name. 149 | * 150 | * @param integer $name 151 | * @throws TeamSpeak3_Adapter_ServerQuery_Exception 152 | * @return Client 153 | */ 154 | public function clientGetByName($name) 155 | { 156 | foreach ($this->clientList() as $client) { 157 | if ($client["client_nickname"] == $name) { 158 | return $client; 159 | } 160 | } 161 | 162 | throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); 163 | } 164 | 165 | /** 166 | * Returns a list of permissions defined for a client in the channel. 167 | * 168 | * @param integer $cldbid 169 | * @param boolean $permsid 170 | * @return void 171 | */ 172 | public function clientPermList($cldbid, $permsid = false) 173 | { 174 | return $this->getParent()->channelClientPermList($this->getId(), $cldbid, $permsid); 175 | } 176 | 177 | /** 178 | * Adds a set of specified permissions to a client in a specific channel. Multiple permissions can be added by 179 | * providing the two parameters of each permission. 180 | * 181 | * @param integer $cldbid 182 | * @param integer $permid 183 | * @param integer $permvalue 184 | * @return void 185 | */ 186 | public function clientPermAssign($cldbid, $permid, $permvalue) 187 | { 188 | return $this->getParent()->channelClientPermAssign($this->getId(), $cldbid, $permid, $permvalue); 189 | } 190 | 191 | /** 192 | * Alias for clientPermAssign(). 193 | * 194 | * @deprecated 195 | */ 196 | public function clientPermAssignByName($cldbid, $permname, $permvalue) 197 | { 198 | return $this->clientPermAssign($cldbid, $permname, $permvalue); 199 | } 200 | 201 | /** 202 | * Removes a set of specified permissions from a client in the channel. Multiple permissions can be removed at once. 203 | * 204 | * @param integer $cldbid 205 | * @param integer $permid 206 | * @return void 207 | */ 208 | public function clientPermRemove($cldbid, $permid) 209 | { 210 | return $this->getParent()->channelClientPermRemove($this->getId(), $cldbid, $permid); 211 | } 212 | 213 | /** 214 | * Alias for clientPermRemove(). 215 | * 216 | * @deprecated 217 | */ 218 | public function clientPermRemoveByName($cldbid, $permname) 219 | { 220 | return $this->clientPermRemove($cldbid, $permname); 221 | } 222 | 223 | /** 224 | * Returns a list of permissions defined for the channel. 225 | * 226 | * @param boolean $permsid 227 | * @return array 228 | */ 229 | public function permList($permsid = false) 230 | { 231 | return $this->getParent()->channelPermList($this->getId(), $permsid); 232 | } 233 | 234 | /** 235 | * Adds a set of specified permissions to the channel. Multiple permissions can be added by 236 | * providing the two parameters of each permission. 237 | * 238 | * @param integer $permid 239 | * @param integer $permvalue 240 | * @return void 241 | */ 242 | public function permAssign($permid, $permvalue) 243 | { 244 | return $this->getParent()->channelPermAssign($this->getId(), $permid, $permvalue); 245 | } 246 | 247 | /** 248 | * Alias for permAssign(). 249 | * 250 | * @deprecated 251 | */ 252 | public function permAssignByName($permname, $permvalue) 253 | { 254 | return $this->permAssign($permname, $permvalue); 255 | } 256 | 257 | /** 258 | * Removes a set of specified permissions from the channel. Multiple permissions can be removed at once. 259 | * 260 | * @param integer $permid 261 | * @return void 262 | */ 263 | public function permRemove($permid) 264 | { 265 | return $this->getParent()->channelPermRemove($this->getId(), $permid); 266 | } 267 | 268 | /** 269 | * Alias for permRemove(). 270 | * 271 | * @deprecated 272 | */ 273 | public function permRemoveByName($permname) 274 | { 275 | return $this->permRemove($permname); 276 | } 277 | 278 | /** 279 | * Returns a list of files and directories stored in the channels file repository. 280 | * 281 | * @param string $cpw 282 | * @param string $path 283 | * @param boolean $recursive 284 | * @return void 285 | */ 286 | public function fileList($cpw = "", $path = "/", $recursive = false) 287 | { 288 | return $this->getParent()->channelFileList($this->getId(), $cpw, $path, $recursive); 289 | } 290 | 291 | /** 292 | * Returns detailed information about the specified file stored in the channels file repository. 293 | * 294 | * @param string $cpw 295 | * @param string $name 296 | * @return array 297 | */ 298 | public function fileInfo($cpw = "", $name = "/") 299 | { 300 | return $this->getParent()->channelFileInfo($this->getId(), $cpw, $name); 301 | } 302 | 303 | /** 304 | * Renames a file in the channels file repository. If the two parameters $tcid and $tcpw are specified, the file 305 | * will be moved into another channels file repository. 306 | * 307 | * @param string $cpw 308 | * @param string $oldname 309 | * @param string $newname 310 | * @param integer $tcid 311 | * @param string $tcpw 312 | * @return void 313 | */ 314 | public function fileRename($cpw = "", $oldname = "/", $newname = "/", $tcid = null, $tcpw = null) 315 | { 316 | return $this->getParent()->channelFileRename($this->getId(), $cpw, $oldname, $newname, $tcid, $tcpw); 317 | } 318 | 319 | /** 320 | * Deletes one or more files stored in the channels file repository. 321 | * 322 | * @param string $cpw 323 | * @param string $path 324 | * @return void 325 | */ 326 | public function fileDelete($cpw = "", $name = "/") 327 | { 328 | return $this->getParent()->channelFileDelete($this->getId(), $cpw, $name); 329 | } 330 | 331 | /** 332 | * Creates new directory in a channels file repository. 333 | * 334 | * @param string $cpw 335 | * @param string $dirname 336 | * @return void 337 | */ 338 | public function dirCreate($cpw = "", $dirname = "/") 339 | { 340 | return $this->getParent()->channelDirCreate($this->getId(), $cpw, $dirname); 341 | } 342 | 343 | /** 344 | * Returns the level of the channel. 345 | * 346 | * @return integer 347 | */ 348 | public function getLevel() 349 | { 350 | return $this->getParent()->channelGetLevel($this->getId()); 351 | } 352 | 353 | /** 354 | * Returns the pathway of the channel which can be used as a clients default channel. 355 | * 356 | * @return string 357 | */ 358 | public function getPathway() 359 | { 360 | return $this->getParent()->channelGetPathway($this->getId()); 361 | } 362 | 363 | /** 364 | * Returns the possible spacer type of the channel. 365 | * 366 | * @return integer 367 | */ 368 | public function spacerGetType() 369 | { 370 | return $this->getParent()->channelSpacerGetType($this->getId()); 371 | } 372 | 373 | /** 374 | * Returns the possible spacer alignment of the channel. 375 | * 376 | * @return integer 377 | */ 378 | public function spacerGetAlign() 379 | { 380 | return $this->getParent()->channelSpacerGetAlign($this->getId()); 381 | } 382 | 383 | /** 384 | * Returns TRUE if the channel is a spacer. 385 | * 386 | * @return boolean 387 | */ 388 | public function isSpacer() 389 | { 390 | return $this->getParent()->channelIsSpacer($this); 391 | } 392 | 393 | /** 394 | * Downloads and returns the channels icon file content. 395 | * 396 | * @return StringHelper 397 | */ 398 | public function iconDownload() 399 | { 400 | if ($this->iconIsLocal("channel_icon_id") || $this["channel_icon_id"] == 0) { 401 | return; 402 | } 403 | 404 | $download = $this->getParent()->transferInitDownload( 405 | rand(0x0000, 0xFFFF), 406 | 0, 407 | $this->iconGetName("channel_icon_id") 408 | ); 409 | $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); 410 | 411 | return $transfer->download($download["ftkey"], $download["size"]); 412 | } 413 | 414 | /** 415 | * Changes the channel configuration using given properties. 416 | * 417 | * @param array $properties 418 | * @return void 419 | */ 420 | public function modify(array $properties) 421 | { 422 | $properties["cid"] = $this->getId(); 423 | 424 | $this->execute("channeledit", $properties); 425 | $this->resetNodeInfo(); 426 | } 427 | 428 | /** 429 | * Sends a text message to all clients in the channel. 430 | * 431 | * @param string $msg 432 | * @param string $cpw 433 | * @return void 434 | */ 435 | public function message($msg, $cpw = null) 436 | { 437 | if ($this->getId() != $this->getParent()->whoamiGet("client_channel_id")) { 438 | $this->getParent()->clientMove($this->getParent()->whoamiGet("client_id"), $this->getId(), $cpw); 439 | } 440 | 441 | $this->execute( 442 | "sendtextmessage", 443 | array("msg" => $msg, "target" => $this->getId(), "targetmode" => TeamSpeak3::TEXTMSG_CHANNEL) 444 | ); 445 | } 446 | 447 | /** 448 | * Deletes the channel. 449 | * 450 | * @param boolean $force 451 | * @return void 452 | */ 453 | public function delete($force = false) 454 | { 455 | $this->getParent()->channelDelete($this->getId(), $force); 456 | } 457 | 458 | /** 459 | * Moves the channel to the parent channel specified with $pid. 460 | * 461 | * @param integer $pid 462 | * @param integer $order 463 | * @return void 464 | */ 465 | public function move($pid, $order = null) 466 | { 467 | $this->getParent()->channelMove($this->getId(), $pid, $order); 468 | } 469 | 470 | /** 471 | * Sends a plugin command to all clients in the channel. 472 | * 473 | * @param string $plugin 474 | * @param string $data 475 | * @param string $cpw 476 | * @param boolean $subscribed 477 | * @return void 478 | */ 479 | public function sendPluginCmd($plugin, $data, $cpw = null, $subscribed = false) 480 | { 481 | if ($this->getId() != $this->getParent()->whoamiGet("client_channel_id")) { 482 | $this->getParent()->clientMove($this->getParent()->whoamiGet("client_id"), $this->getId(), $cpw); 483 | } 484 | 485 | $this->execute( 486 | "plugincmd", 487 | array( 488 | "name" => $plugin, 489 | "data" => $data, 490 | "targetmode" => $subscribed ? TeamSpeak3::PLUGINCMD_CHANNEL_SUBSCRIBED : TeamSpeak3::PLUGINCMD_CHANNEL 491 | ) 492 | ); 493 | } 494 | 495 | /** 496 | * @ignore 497 | */ 498 | protected function fetchNodeList() 499 | { 500 | $this->nodeList = array(); 501 | 502 | if ($this->getParent()->getLoadClientlistFirst()) { 503 | foreach ($this->clientList() as $client) { 504 | if ($client["cid"] == $this->getId()) { 505 | $this->nodeList[] = $client; 506 | } 507 | } 508 | 509 | foreach ($this->subChannelList() as $channel) { 510 | if ($channel["pid"] == $this->getId()) { 511 | $this->nodeList[] = $channel; 512 | } 513 | } 514 | } else { 515 | foreach ($this->subChannelList() as $channel) { 516 | if ($channel["pid"] == $this->getId()) { 517 | $this->nodeList[] = $channel; 518 | } 519 | } 520 | 521 | foreach ($this->clientList() as $client) { 522 | if ($client["cid"] == $this->getId()) { 523 | $this->nodeList[] = $client; 524 | } 525 | } 526 | } 527 | } 528 | 529 | /** 530 | * @ignore 531 | */ 532 | protected function fetchNodeInfo() 533 | { 534 | $this->nodeInfo = array_merge( 535 | $this->nodeInfo, 536 | $this->execute("channelinfo", array("cid" => $this->getId()))->toList() 537 | ); 538 | } 539 | 540 | /** 541 | * Returns a unique identifier for the node which can be used as a HTML property. 542 | * 543 | * @return string 544 | */ 545 | public function getUniqueId() 546 | { 547 | return $this->getParent()->getUniqueId() . "_ch" . $this->getId(); 548 | } 549 | 550 | /** 551 | * Returns the name of a possible icon to display the node object. 552 | * 553 | * @return string 554 | */ 555 | public function getIcon() 556 | { 557 | if ($this["channel_maxclients"] != -1 && $this["channel_maxclients"] <= $this["total_clients"]) { 558 | return "channel_full"; 559 | } elseif ($this["channel_flag_password"]) { 560 | return "channel_pass"; 561 | } else { 562 | return "channel_open"; 563 | } 564 | } 565 | 566 | /** 567 | * Returns a symbol representing the node. 568 | * 569 | * @return string 570 | */ 571 | public function getSymbol() 572 | { 573 | return "#"; 574 | } 575 | 576 | /** 577 | * Returns a string representation of this node. 578 | * 579 | * @return string 580 | */ 581 | public function __toString() 582 | { 583 | return (string)$this["channel_name"]; 584 | } 585 | } 586 | 587 | -------------------------------------------------------------------------------- /TeamSpeak3/Node/Channelgroup.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Node; 29 | 30 | use TeamSpeak3\TeamSpeak3; 31 | 32 | /** 33 | * @class Channelgroug 34 | * @brief Class describing a TeamSpeak 3 channel group and all it's parameters. 35 | */ 36 | class Channelgroup extends AbstractNode 37 | { 38 | /** 39 | * The Channelgroug constructor. 40 | * 41 | * @param Server $server 42 | * @param array $info 43 | * @param string $index 44 | * @throws TeamSpeak3_Adapter_ServerQuery_Exception 45 | * @return Channelgroug 46 | */ 47 | public function __construct(Server $server, array $info, $index = "cgid") 48 | { 49 | $this->parent = $server; 50 | $this->nodeInfo = $info; 51 | 52 | if (!array_key_exists($index, $this->nodeInfo)) { 53 | throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); 54 | } 55 | 56 | $this->nodeId = $this->nodeInfo[$index]; 57 | } 58 | 59 | /** 60 | * Renames the channel group specified. 61 | * 62 | * @param string $name 63 | * @return void 64 | */ 65 | public function rename($name) 66 | { 67 | return $this->getParent()->channelGroupRename($this->getId(), $name); 68 | } 69 | 70 | /** 71 | * Deletes the channel group. If $force is set to TRUE, the channel group will be 72 | * deleted even if there are clients within. 73 | * 74 | * @param boolean $force 75 | * @return void 76 | */ 77 | public function delete($force = false) 78 | { 79 | $this->getParent()->channelGroupDelete($this->getId(), $force); 80 | } 81 | 82 | /** 83 | * Creates a copy of the channel group and returns the new groups ID. 84 | * 85 | * @param string $name 86 | * @param integer $tcgid 87 | * @param integer $type 88 | * @return integer 89 | */ 90 | public function copy($name = null, $tcgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) 91 | { 92 | return $this->getParent()->channelGroupCopy($this->getId(), $name, $tcgid, $type); 93 | } 94 | 95 | /** 96 | * Returns a list of permissions assigned to the channel group. 97 | * 98 | * @param boolean $permsid 99 | * @return array 100 | */ 101 | public function permList($permsid = false) 102 | { 103 | return $this->getParent()->channelGroupPermList($this->getId(), $permsid); 104 | } 105 | 106 | /** 107 | * Adds a set of specified permissions to the channel group. Multiple permissions 108 | * can be added by providing the two parameters of each permission in separate arrays. 109 | * 110 | * @param integer $permid 111 | * @param integer $permvalue 112 | * @return void 113 | */ 114 | public function permAssign($permid, $permvalue) 115 | { 116 | return $this->getParent()->channelGroupPermAssign($this->getId(), $permid, $permvalue); 117 | } 118 | 119 | /** 120 | * Alias for permAssign(). 121 | * 122 | * @deprecated 123 | */ 124 | public function permAssignByName($permname, $permvalue) 125 | { 126 | return $this->permAssign($permname, $permvalue); 127 | } 128 | 129 | /** 130 | * Removes a set of specified permissions from the channel group. Multiple 131 | * permissions can be removed at once. 132 | * 133 | * @param integer $permid 134 | * @return void 135 | */ 136 | public function permRemove($permid) 137 | { 138 | return $this->getParent()->channelGroupPermRemove($this->getId(), $permid); 139 | } 140 | 141 | /** 142 | * Alias for permAssign(). 143 | * 144 | * @deprecated 145 | */ 146 | public function permRemoveByName($permname) 147 | { 148 | return $this->permRemove($permname); 149 | } 150 | 151 | /** 152 | * Returns a list of clients assigned to the server group specified. 153 | * 154 | * @return array 155 | */ 156 | public function clientList() 157 | { 158 | return $this->getParent()->channelGroupClientList($this->getId()); 159 | } 160 | 161 | /** 162 | * Alias for privilegeKeyCreate(). 163 | * 164 | * @deprecated 165 | */ 166 | public function tokenCreate($cid, $description = null, $customset = null) 167 | { 168 | return $this->privilegeKeyCreate($cid, $description, $customset); 169 | } 170 | 171 | /** 172 | * Creates a new privilege key (token) for the channel group and returns the key. 173 | * 174 | * @param integer $cid 175 | * @param string $description 176 | * @param string $customset 177 | * @return StringHelper 178 | */ 179 | public function privilegeKeyCreate($cid, $description = null, $customset = null) 180 | { 181 | return $this->getParent()->privilegeKeyCreate( 182 | TeamSpeak3::TOKEN_CHANNELGROUP, 183 | $this->getId(), 184 | $cid, 185 | $description, 186 | $customset 187 | ); 188 | } 189 | 190 | /** 191 | * Sends a text message to all clients residing in the channel group on the virtual server. 192 | * 193 | * @param string $msg 194 | * @return void 195 | */ 196 | public function message($msg) 197 | { 198 | foreach ($this as $client) { 199 | try { 200 | $this->execute( 201 | "sendtextmessage", 202 | array("msg" => $msg, "target" => $client, "targetmode" => TeamSpeak3::TEXTMSG_CLIENT) 203 | ); 204 | } catch (TeamSpeak3_Adapter_ServerQuery_Exception $e) { 205 | /* ERROR_client_invalid_id */ 206 | if ($e->getCode() != 0x0200) { 207 | throw $e; 208 | } 209 | } 210 | } 211 | } 212 | 213 | /** 214 | * Downloads and returns the channel groups icon file content. 215 | * 216 | * @return StringHelper 217 | */ 218 | public function iconDownload() 219 | { 220 | if ($this->iconIsLocal("iconid") || $this["iconid"] == 0) { 221 | return; 222 | } 223 | 224 | $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("iconid")); 225 | $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); 226 | 227 | return $transfer->download($download["ftkey"], $download["size"]); 228 | } 229 | 230 | /** 231 | * @ignore 232 | */ 233 | protected function fetchNodeList() 234 | { 235 | $this->nodeList = array(); 236 | 237 | foreach ($this->getParent()->clientList() as $client) { 238 | if ($client["client_channel_group_id"] == $this->getId()) { 239 | $this->nodeList[] = $client; 240 | } 241 | } 242 | } 243 | 244 | /** 245 | * Returns a unique identifier for the node which can be used as a HTML property. 246 | * 247 | * @return string 248 | */ 249 | public function getUniqueId() 250 | { 251 | return $this->getParent()->getUniqueId() . "_cg" . $this->getId(); 252 | } 253 | 254 | /** 255 | * Returns the name of a possible icon to display the node object. 256 | * 257 | * @return string 258 | */ 259 | public function getIcon() 260 | { 261 | return "group_channel"; 262 | } 263 | 264 | /** 265 | * Returns a symbol representing the node. 266 | * 267 | * @return string 268 | */ 269 | public function getSymbol() 270 | { 271 | return "%"; 272 | } 273 | 274 | /** 275 | * Returns a string representation of this node. 276 | * 277 | * @return string 278 | */ 279 | public function __toString() 280 | { 281 | return (string)$this["name"]; 282 | } 283 | } 284 | 285 | -------------------------------------------------------------------------------- /TeamSpeak3/Node/Client.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Node; 29 | 30 | use TeamSpeak3\Helper\StringHelper; 31 | use TeamSpeak3\TeamSpeak3; 32 | 33 | /** 34 | * @class Client 35 | * @brief Class describing a TeamSpeak 3 client and all it's parameters. 36 | */ 37 | class Client extends AbstractNode 38 | { 39 | /** 40 | * The Client constructor. 41 | * 42 | * @param Server $server 43 | * @param array $info 44 | * @param string $index 45 | * @throws TeamSpeak3_Adapter_ServerQuery_Exception 46 | * @return Client 47 | */ 48 | public function __construct(Server $server, array $info, $index = "clid") 49 | { 50 | $this->parent = $server; 51 | $this->nodeInfo = $info; 52 | 53 | if (!array_key_exists($index, $this->nodeInfo)) { 54 | throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); 55 | } 56 | 57 | $this->nodeId = $this->nodeInfo[$index]; 58 | } 59 | 60 | /** 61 | * Changes the clients properties using given properties. 62 | * 63 | * @param array $properties 64 | * @return void 65 | */ 66 | public function modify(array $properties) 67 | { 68 | $properties["clid"] = $this->getId(); 69 | 70 | $this->execute("clientedit", $properties); 71 | $this->resetNodeInfo(); 72 | } 73 | 74 | /** 75 | * Changes the clients properties using given properties. 76 | * 77 | * @param array $properties 78 | * @return void 79 | */ 80 | public function modifyDb(array $properties) 81 | { 82 | return $this->getParent()->clientModifyDb($this["client_database_id"], $properties); 83 | } 84 | 85 | /** 86 | * Deletes the clients properties from the database. 87 | * 88 | * @return void 89 | */ 90 | public function deleteDb() 91 | { 92 | return $this->getParent()->clientDeleteDb($this["client_database_id"]); 93 | } 94 | 95 | /** 96 | * Returns a list of properties from the database for the client. 97 | * 98 | * @return array 99 | */ 100 | public function infoDb() 101 | { 102 | return $this->getParent()->clientInfoDb($this["client_database_id"]); 103 | } 104 | 105 | /** 106 | * Sends a text message to the client. 107 | * 108 | * @param string $msg 109 | * @return void 110 | */ 111 | public function message($msg) 112 | { 113 | $this->execute( 114 | "sendtextmessage", 115 | array("msg" => $msg, "target" => $this->getId(), "targetmode" => TeamSpeak3::TEXTMSG_CLIENT) 116 | ); 117 | } 118 | 119 | /** 120 | * Moves the client to another channel. 121 | * 122 | * @param integer $cid 123 | * @param string $cpw 124 | * @return void 125 | */ 126 | public function move($cid, $cpw = null) 127 | { 128 | return $this->getParent()->clientMove($this->getId(), $cid, $cpw); 129 | } 130 | 131 | /** 132 | * Kicks the client from his currently joined channel or from the server. 133 | * 134 | * @param integer $reasonid 135 | * @param string $reasonmsg 136 | * @return void 137 | */ 138 | public function kick($reasonid = TeamSpeak3::KICK_CHANNEL, $reasonmsg = null) 139 | { 140 | return $this->getParent()->clientKick($this->getId(), $reasonid, $reasonmsg); 141 | } 142 | 143 | /** 144 | * Sends a poke message to the client. 145 | * 146 | * @param string $msg 147 | * @return void 148 | */ 149 | public function poke($msg) 150 | { 151 | return $this->getParent()->clientPoke($this->getId(), $msg); 152 | } 153 | 154 | /** 155 | * Bans the client from the server. Please note that this will create two separate 156 | * ban rules for the targeted clients IP address and his unique identifier. 157 | * 158 | * @param integer $timeseconds 159 | * @param string $reason 160 | * @return array 161 | */ 162 | public function ban($timeseconds = null, $reason = null) 163 | { 164 | return $this->getParent()->clientBan($this->getId(), $timeseconds, $reason); 165 | } 166 | 167 | /** 168 | * Returns a list of custom properties for the client. 169 | * 170 | * @return array 171 | */ 172 | public function customInfo() 173 | { 174 | return $this->getParent()->customInfo($this["client_database_id"]); 175 | } 176 | 177 | /** 178 | * Returns an array containing the permission overview of the client. 179 | * 180 | * @param integer $cid 181 | * @return array 182 | */ 183 | public function permOverview($cid) 184 | { 185 | return $this->execute( 186 | "permoverview", 187 | array("cldbid" => $this["client_database_id"], "cid" => $cid, "permid" => 0) 188 | )->toArray(); 189 | } 190 | 191 | /** 192 | * Returns a list of permissions defined for the client. 193 | * 194 | * @param boolean $permsid 195 | * @return array 196 | */ 197 | public function permList($permsid = false) 198 | { 199 | return $this->getParent()->clientPermList($this["client_database_id"], $permsid); 200 | } 201 | 202 | /** 203 | * Adds a set of specified permissions to the client. Multiple permissions can be added by providing 204 | * the three parameters of each permission. 205 | * 206 | * @param integer $permid 207 | * @param integer $permvalue 208 | * @param integer $permskip 209 | * @return void 210 | */ 211 | public function permAssign($permid, $permvalue, $permskip = false) 212 | { 213 | return $this->getParent()->clientPermAssign($this["client_database_id"], $permid, $permvalue, $permskip); 214 | } 215 | 216 | /** 217 | * Alias for permAssign(). 218 | * 219 | * @deprecated 220 | */ 221 | public function permAssignByName($permname, $permvalue, $permskip = false) 222 | { 223 | return $this->permAssign($permname, $permvalue, $permskip); 224 | } 225 | 226 | /** 227 | * Removes a set of specified permissions from a client. Multiple permissions can be removed at once. 228 | * 229 | * @param integer $permid 230 | * @return void 231 | */ 232 | public function permRemove($permid) 233 | { 234 | return $this->getParent()->clientPermRemove($this["client_database_id"], $permid); 235 | } 236 | 237 | /** 238 | * Alias for permRemove(). 239 | * 240 | * @deprecated 241 | */ 242 | public function permRemoveByName($permname) 243 | { 244 | return $this->permRemove($permname); 245 | } 246 | 247 | /** 248 | * Sets the channel group of a client to the ID specified. 249 | * 250 | * @param integer $cid 251 | * @param integer $cgid 252 | * @return void 253 | */ 254 | public function setChannelGroup($cid, $cgid) 255 | { 256 | return $this->getParent()->clientSetChannelGroup($this["client_database_id"], $cid, $cgid); 257 | } 258 | 259 | /** 260 | * Adds the client to the server group specified with $sgid. 261 | * 262 | * @param integer $sgid 263 | * @return void 264 | */ 265 | public function addServerGroup($sgid) 266 | { 267 | return $this->getParent()->serverGroupClientAdd($sgid, $this["client_database_id"]); 268 | } 269 | 270 | /** 271 | * Removes the client from the server group specified with $sgid. 272 | * 273 | * @param integer $sgid 274 | * @return void 275 | */ 276 | public function remServerGroup($sgid) 277 | { 278 | return $this->getParent()->serverGroupClientDel($sgid, $this["client_database_id"]); 279 | } 280 | 281 | /** 282 | * Returns the possible name of the clients avatar. 283 | * 284 | * @return StringHelper 285 | */ 286 | public function avatarGetName() 287 | { 288 | return new StringHelper("/avatar_" . $this["client_base64HashClientUID"]); 289 | } 290 | 291 | /** 292 | * Downloads and returns the clients avatar file content. 293 | * 294 | * @return StringHelper 295 | */ 296 | public function avatarDownload() 297 | { 298 | if ($this["client_flag_avatar"] == 0) { 299 | return; 300 | } 301 | 302 | $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->avatarGetName()); 303 | $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); 304 | 305 | return $transfer->download($download["ftkey"], $download["size"]); 306 | } 307 | 308 | /** 309 | * Returns a list of client connections using the same identity as this client. 310 | * 311 | * @return array 312 | */ 313 | public function getClones() 314 | { 315 | return $this->execute("clientgetids", array("cluid" => $this["client_unique_identifier"]))->toAssocArray( 316 | "clid" 317 | ); 318 | } 319 | 320 | /** 321 | * Returns the revision/build number from the clients version string. 322 | * 323 | * @return integer 324 | */ 325 | public function getRev() 326 | { 327 | return $this["client_type"] ? null : $this["client_version"]->section("[", 1)->filterDigits(); 328 | } 329 | 330 | /** 331 | * Returns all server and channel groups the client is currently residing in. 332 | * 333 | * @return array 334 | */ 335 | public function memberOf() 336 | { 337 | $groups = array($this->getParent()->channelGroupGetById($this["client_channel_group_id"])); 338 | 339 | foreach (explode(",", $this["client_servergroups"]) as $sgid) { 340 | $groups[] = $this->getParent()->serverGroupGetById($sgid); 341 | } 342 | 343 | return $groups; 344 | } 345 | 346 | /** 347 | * Downloads and returns the clients icon file content. 348 | * 349 | * @return StringHelper 350 | */ 351 | public function iconDownload() 352 | { 353 | if ($this->iconIsLocal("client_icon_id") || $this["client_icon_id"] == 0) { 354 | return; 355 | } 356 | 357 | $download = $this->getParent()->transferInitDownload( 358 | rand(0x0000, 0xFFFF), 359 | 0, 360 | $this->iconGetName("client_icon_id") 361 | ); 362 | $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); 363 | 364 | return $transfer->download($download["ftkey"], $download["size"]); 365 | } 366 | 367 | /** 368 | * Sends a plugin command to the client. 369 | * 370 | * @param string $plugin 371 | * @param string $data 372 | * @return void 373 | */ 374 | public function sendPluginCmd($plugin, $data) 375 | { 376 | $this->execute( 377 | "plugincmd", 378 | array( 379 | "name" => $plugin, 380 | "data" => $data, 381 | "targetmode" => TeamSpeak3::PLUGINCMD_CLIENT, 382 | "target" => $this->getId() 383 | ) 384 | ); 385 | } 386 | 387 | /** 388 | * @ignore 389 | */ 390 | protected function fetchNodeInfo() 391 | { 392 | if ($this["client_type"] == 1) { 393 | return; 394 | } 395 | 396 | $this->nodeInfo = array_merge( 397 | $this->nodeInfo, 398 | $this->execute("clientinfo", array("clid" => $this->getId()))->toList() 399 | ); 400 | } 401 | 402 | /** 403 | * Returns a unique identifier for the node which can be used as a HTML property. 404 | * 405 | * @return string 406 | */ 407 | public function getUniqueId() 408 | { 409 | return $this->getParent()->getUniqueId() . "_cl" . $this->getId(); 410 | } 411 | 412 | /** 413 | * Returns the name of a possible icon to display the node object. 414 | * 415 | * @return string 416 | */ 417 | public function getIcon() 418 | { 419 | if ($this["client_type"]) { 420 | return "client_query"; 421 | } elseif ($this["client_away"]) { 422 | return "client_away"; 423 | } elseif (!$this["client_output_hardware"]) { 424 | return "client_snd_disabled"; 425 | } elseif ($this["client_output_muted"]) { 426 | return "client_snd_muted"; 427 | } elseif (!$this["client_input_hardware"]) { 428 | return "client_mic_disabled"; 429 | } elseif ($this["client_input_muted"]) { 430 | return "client_mic_muted"; 431 | } elseif ($this["client_is_channel_commander"]) { 432 | return $this["client_flag_talking"] ? "client_cc_talk" : "client_cc_idle"; 433 | } else { 434 | return $this["client_flag_talking"] ? "client_talk" : "client_idle"; 435 | } 436 | } 437 | 438 | /** 439 | * Returns a symbol representing the node. 440 | * 441 | * @return string 442 | */ 443 | public function getSymbol() 444 | { 445 | return "@"; 446 | } 447 | 448 | /** 449 | * Returns a string representation of this node. 450 | * 451 | * @return string 452 | */ 453 | public function __toString() 454 | { 455 | return (string)$this["client_nickname"]; 456 | } 457 | } 458 | 459 | -------------------------------------------------------------------------------- /TeamSpeak3/Node/Servergroup.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Node; 29 | 30 | use TeamSpeak3\TeamSpeak3; 31 | use TeamSpeak3\Helper\StringHelper; 32 | use TeamSpeak3\Ts3Exception; 33 | 34 | /** 35 | * @class Servergroup 36 | * @brief Class describing a TeamSpeak 3 server group and all it's parameters. 37 | */ 38 | class Servergroup extends AbstractNode 39 | { 40 | /** 41 | * The Servergroup constructor. 42 | * 43 | * @param Server $server 44 | * @param array $info 45 | * @param string $index 46 | * @throws Ts3Exception 47 | * @return Servergroup 48 | */ 49 | public function __construct(Server $server, array $info, $index = "sgid") 50 | { 51 | $this->parent = $server; 52 | $this->nodeInfo = $info; 53 | 54 | if (!array_key_exists($index, $this->nodeInfo)) { 55 | throw new Ts3Exception("invalid groupID", 0xA00); 56 | } 57 | 58 | $this->nodeId = $this->nodeInfo[$index]; 59 | } 60 | 61 | /** 62 | * Renames the server group specified. 63 | * 64 | * @param string $name 65 | */ 66 | public function rename($name) 67 | { 68 | return $this->getParent()->serverGroupRename($this->getId(), $name); 69 | } 70 | 71 | /** 72 | * Deletes the server group. If $force is set to 1, the server group will be 73 | * deleted even if there are clients within. 74 | * 75 | * @param boolean $force 76 | * @return void 77 | */ 78 | public function delete($force = false) 79 | { 80 | $this->getParent()->serverGroupDelete($this->getId(), $force); 81 | } 82 | 83 | /** 84 | * Creates a copy of the server group and returns the new groups ID. 85 | * 86 | * @param string $name 87 | * @param integer $tsgid 88 | * @param integer $type 89 | * @return integer 90 | */ 91 | public function copy($name = null, $tsgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) 92 | { 93 | return $this->getParent()->serverGroupCopy($this->getId(), $name, $tsgid, $type); 94 | } 95 | 96 | /** 97 | * Returns a list of permissions assigned to the server group. 98 | * 99 | * @param boolean $permsid 100 | * @return array 101 | */ 102 | public function permList($permsid = false) 103 | { 104 | return $this->getParent()->serverGroupPermList($this->getId(), $permsid); 105 | } 106 | 107 | /** 108 | * Adds a set of specified permissions to the server group. Multiple permissions 109 | * can be added by providing the four parameters of each permission in separate arrays. 110 | * 111 | * @param integer $permid 112 | * @param integer $permvalue 113 | * @param bool|int $permnegated 114 | * @param bool|int $permskip 115 | */ 116 | public function permAssign($permid, $permvalue, $permnegated = false, $permskip = false) 117 | { 118 | return $this->getParent()->serverGroupPermAssign($this->getId(), $permid, $permvalue, $permnegated, $permskip); 119 | } 120 | 121 | /** 122 | * Alias for permAssign(). 123 | * 124 | * @deprecated 125 | */ 126 | public function permAssignByName($permname, $permvalue, $permnegated = false, $permskip = false) 127 | { 128 | return $this->permAssign($permname, $permvalue, $permnegated, $permskip); 129 | } 130 | 131 | /** 132 | * Removes a set of specified permissions from the server group. Multiple 133 | * permissions can be removed at once. 134 | * 135 | * @param integer $permid 136 | */ 137 | public function permRemove($permid) 138 | { 139 | return $this->getParent()->serverGroupPermRemove($this->getId(), $permid); 140 | } 141 | 142 | /** 143 | * Alias for permRemove(). 144 | * 145 | * @deprecated 146 | */ 147 | public function permRemoveByName($permname) 148 | { 149 | return $this->permRemove($permname); 150 | } 151 | 152 | /** 153 | * Returns a list of clients assigned to the server group specified. 154 | * 155 | * @return array 156 | */ 157 | public function clientList() 158 | { 159 | return $this->getParent()->serverGroupClientList($this->getId()); 160 | } 161 | 162 | /** 163 | * Adds a client to the server group specified. Please note that a client cannot be 164 | * added to default groups or template groups. 165 | * 166 | * @param integer $cldbid 167 | */ 168 | public function clientAdd($cldbid) 169 | { 170 | return $this->getParent()->serverGroupClientAdd($this->getId(), $cldbid); 171 | } 172 | 173 | /** 174 | * Removes a client from the server group. 175 | * 176 | * @param integer $cldbid 177 | */ 178 | public function clientDel($cldbid) 179 | { 180 | return $this->getParent()->serverGroupClientDel($this->getId(), $cldbid); 181 | } 182 | 183 | /** 184 | * Alias for privilegeKeyCreate(). 185 | * 186 | * @deprecated 187 | */ 188 | public function tokenCreate($description = null, $customset = null) 189 | { 190 | return $this->privilegeKeyCreate($description, $customset); 191 | } 192 | 193 | /** 194 | * Creates a new privilege key (token) for the server group and returns the key. 195 | * 196 | * @param string $description 197 | * @param string $customset 198 | * @return StringHelper 199 | */ 200 | public function privilegeKeyCreate($description = null, $customset = null) 201 | { 202 | return $this->getParent()->privilegeKeyCreate( 203 | TeamSpeak3::TOKEN_SERVERGROUP, 204 | $this->getId(), 205 | 0, 206 | $description, 207 | $customset 208 | ); 209 | } 210 | 211 | /** 212 | * Sends a text message to all clients residing in the server group on the virtual server. 213 | * 214 | * @param string $msg 215 | * @throws \Exception 216 | * @throws \Teamspeak3\Ts3Exception 217 | * @return void 218 | */ 219 | public function message($msg) 220 | { 221 | foreach ($this as $client) { 222 | try { 223 | $this->execute( 224 | "sendtextmessage", 225 | array("msg" => $msg, "target" => $client, "targetmode" => TeamSpeak3::TEXTMSG_CLIENT) 226 | ); 227 | } catch (Ts3Exception $e) { 228 | /* ERROR_client_invalid_id */ 229 | if ($e->getCode() != 0x0200) { 230 | throw $e; 231 | } 232 | } 233 | } 234 | } 235 | 236 | /** 237 | * Downloads and returns the server groups icon file content. 238 | * 239 | * @return StringHelper 240 | */ 241 | public function iconDownload() 242 | { 243 | if ($this->iconIsLocal("iconid") || $this["iconid"] == 0) { 244 | return null; 245 | } 246 | 247 | $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("iconid")); 248 | $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); 249 | 250 | return $transfer->download($download["ftkey"], $download["size"]); 251 | } 252 | 253 | /** 254 | * @ignore 255 | */ 256 | protected function fetchNodeList() 257 | { 258 | $this->nodeList = array(); 259 | 260 | foreach ($this->getParent()->clientList() as $client) { 261 | if (in_array($this->getId(), explode(",", $client["client_servergroups"]))) { 262 | $this->nodeList[] = $client; 263 | } 264 | } 265 | } 266 | 267 | /** 268 | * Returns a unique identifier for the node which can be used as a HTML property. 269 | * 270 | * @return string 271 | */ 272 | public function getUniqueId() 273 | { 274 | return $this->getParent()->getUniqueId() . "_sg" . $this->getId(); 275 | } 276 | 277 | /** 278 | * Returns the name of a possible icon to display the node object. 279 | * 280 | * @return string 281 | */ 282 | public function getIcon() 283 | { 284 | return "group_server"; 285 | } 286 | 287 | /** 288 | * Returns a symbol representing the node. 289 | * 290 | * @return string 291 | */ 292 | public function getSymbol() 293 | { 294 | return "%"; 295 | } 296 | 297 | /** 298 | * Returns a string representation of this node. 299 | * 300 | * @return string 301 | */ 302 | public function __toString() 303 | { 304 | return (string)$this["name"]; 305 | } 306 | } 307 | 308 | -------------------------------------------------------------------------------- /TeamSpeak3/Transport/AbstractTransport.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Transport; 29 | 30 | use TeamSpeak3\Helper\Signal; 31 | use TeamSpeak3\Helper\StringHelper; 32 | use TeamSpeak3\Ts3Exception; 33 | use TeamSpeak3\Adapter\AbstractAdapter; 34 | 35 | /** 36 | * @class AbstractTransport 37 | * @brief Abstract class for connecting to a TeamSpeak 3 Server through different ways of transport. 38 | */ 39 | abstract class AbstractTransport 40 | { 41 | /** 42 | * Stores user-provided configuration settings. 43 | * 44 | * @var array 45 | */ 46 | protected $config = null; 47 | 48 | /** 49 | * Stores the stream resource of the connection. 50 | * 51 | * @var resource 52 | */ 53 | protected $stream = null; 54 | 55 | /** 56 | * Stores the AbstractAdapter object using this transport. 57 | * 58 | * @var AbstractAdapter 59 | */ 60 | protected $adapter = null; 61 | 62 | /** 63 | * The AbstractTransport constructor. 64 | * 65 | * @param array $config 66 | * @throws Ts3Exception 67 | * @return AbstractTransport 68 | */ 69 | public function __construct(array $config) 70 | { 71 | if (!array_key_exists("host", $config)) { 72 | throw new Ts3Exception( 73 | "config must have a key for 'host' which specifies the server host name" 74 | ); 75 | } 76 | 77 | if (!array_key_exists("port", $config)) { 78 | throw new Ts3Exception( 79 | "config must have a key for 'port' which specifies the server port number" 80 | ); 81 | } 82 | 83 | if (!array_key_exists("timeout", $config)) { 84 | $config["timeout"] = 10; 85 | } 86 | 87 | if (!array_key_exists("blocking", $config)) { 88 | $config["blocking"] = 1; 89 | } 90 | 91 | $this->config = $config; 92 | } 93 | 94 | /** 95 | * Commit pending data. 96 | * 97 | * @return array 98 | */ 99 | public function __sleep() 100 | { 101 | return array("config"); 102 | } 103 | 104 | /** 105 | * Reconnects to the remote server. 106 | * 107 | * @return void 108 | */ 109 | public function __wakeup() 110 | { 111 | $this->connect(); 112 | } 113 | 114 | /** 115 | * The AbstractTransport destructor. 116 | * 117 | * @return void 118 | */ 119 | public function __destruct() 120 | { 121 | if ($this->adapter instanceof AbstractAdapter) { 122 | $this->adapter->__destruct(); 123 | } 124 | 125 | $this->disconnect(); 126 | } 127 | 128 | /** 129 | * Connects to a remote server. 130 | * 131 | * @throws Ts3Exception 132 | * @return void 133 | */ 134 | abstract public function connect(); 135 | 136 | /** 137 | * Disconnects from a remote server. 138 | * 139 | * @return void 140 | */ 141 | abstract public function disconnect(); 142 | 143 | /** 144 | * Reads data from the stream. 145 | * 146 | * @param integer $length 147 | * @throws Ts3Exception 148 | * @return StringHelper 149 | */ 150 | abstract public function read($length = 4096); 151 | 152 | /** 153 | * Writes data to the stream. 154 | * 155 | * @param string $data 156 | * @return void 157 | */ 158 | abstract public function send($data); 159 | 160 | /** 161 | * Returns the underlying stream resource. 162 | * 163 | * @return resource 164 | */ 165 | public function getStream() 166 | { 167 | return $this->stream; 168 | } 169 | 170 | /** 171 | * Returns the configuration variables in this adapter. 172 | * 173 | * @param string $key 174 | * @param mixed $default 175 | * @return array 176 | */ 177 | public function getConfig($key = null, $default = null) 178 | { 179 | if ($key !== null) { 180 | return array_key_exists($key, $this->config) ? $this->config[$key] : $default; 181 | } 182 | 183 | return $this->config; 184 | } 185 | 186 | /** 187 | * Sets the AbstractAdapter object using this transport. 188 | * 189 | * @param AbstractAdapter $adapter 190 | * @return void 191 | */ 192 | public function setAdapter(AbstractAdapter $adapter) 193 | { 194 | $this->adapter = $adapter; 195 | } 196 | 197 | /** 198 | * Returns the AbstractAdapter object using this transport. 199 | * 200 | * @return AbstractAdapter 201 | */ 202 | public function getAdapter() 203 | { 204 | return $this->adapter; 205 | } 206 | 207 | /** 208 | * Returns the adapter type. 209 | * 210 | * @return string 211 | */ 212 | public function getAdapterType() 213 | { 214 | if ($this->adapter instanceof AbstractAdapter) { 215 | $string = StringHelper::factory(get_class($this->adapter)); 216 | 217 | return $string->substr($string->findLast("\\"))->replace(array("\\", " "), "")->toString(); 218 | } 219 | 220 | return "Unknown"; 221 | } 222 | 223 | /** 224 | * Returns header/meta data from stream pointer. 225 | * 226 | * @throws Ts3Exception 227 | * @return array 228 | */ 229 | public function getMetaData() 230 | { 231 | if ($this->stream === null) { 232 | throw new Ts3Exception("unable to retrieve header/meta data from stream pointer"); 233 | } 234 | 235 | return stream_get_meta_data($this->stream); 236 | } 237 | 238 | /** 239 | * Returns TRUE if the transport is connected. 240 | * 241 | * @return boolean 242 | */ 243 | public function isConnected() 244 | { 245 | return (is_resource($this->stream)) ? true : false; 246 | } 247 | 248 | /** 249 | * Blocks a stream until data is available for reading if the stream is connected 250 | * in non-blocking mode. 251 | * 252 | * @param integer $time 253 | * @return void 254 | */ 255 | protected function waitForReadyRead($time = 0) 256 | { 257 | if (!$this->isConnected() || $this->config["blocking"]) { 258 | return; 259 | } 260 | 261 | do { 262 | $read = array($this->stream); 263 | $null = null; 264 | 265 | if ($time) { 266 | Signal::getInstance()->emit( 267 | strtolower($this->getAdapterType()) . "WaitTimeout", 268 | $time, 269 | $this->getAdapter() 270 | ); 271 | } 272 | 273 | $time = $time + $this->config["timeout"]; 274 | } while (@stream_select($read, $null, $null, $this->config["timeout"]) == 0); 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /TeamSpeak3/Transport/TCP.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Transport; 29 | 30 | use TeamSpeak3\Helper\Signal; 31 | use TeamSpeak3\Helper\StringHelper; 32 | use TeamSpeak3\Ts3Exception; 33 | 34 | /** 35 | * @class TCP 36 | * @brief Class for connecting to a remote server through TCP. 37 | */ 38 | class TCP extends AbstractTransport 39 | { 40 | /** 41 | * Connects to a remote server. 42 | * 43 | * @throws Ts3Exception 44 | * @return void 45 | */ 46 | public function connect() 47 | { 48 | if ($this->stream !== null) { 49 | return; 50 | } 51 | 52 | $host = strval($this->config["host"]); 53 | $port = strval($this->config["port"]); 54 | 55 | $address = "tcp://" . $host . ":" . $port; 56 | $timeout = intval($this->config["timeout"]); 57 | 58 | $this->stream = @stream_socket_client($address, $errno, $errstr, $timeout); 59 | 60 | if ($this->stream === false) { 61 | throw new Ts3Exception( 62 | StringHelper::factory($errstr)->toUtf8()->toString(), 63 | $errno 64 | ); 65 | } 66 | 67 | @stream_set_timeout($this->stream, $timeout); 68 | @stream_set_blocking($this->stream, $this->config["blocking"] ? 1 : 0); 69 | } 70 | 71 | /** 72 | * Disconnects from a remote server. 73 | * 74 | * @return void 75 | */ 76 | public function disconnect() 77 | { 78 | if ($this->stream === null) { 79 | return; 80 | } 81 | 82 | $this->stream = null; 83 | 84 | Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "Disconnected"); 85 | } 86 | 87 | /** 88 | * Reads data from the stream. 89 | * 90 | * @param integer $length 91 | * @throws Ts3Exception 92 | * @return StringHelper 93 | */ 94 | public function read($length = 4096) 95 | { 96 | $this->connect(); 97 | $this->waitForReadyRead(); 98 | 99 | $data = @stream_get_contents($this->stream, $length); 100 | 101 | Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataRead", $data); 102 | 103 | if ($data === false) { 104 | throw new Ts3Exception( 105 | "connection to server '" . $this->config["host"] . ":" . $this->config["port"] . "' lost" 106 | ); 107 | } 108 | 109 | return new StringHelper($data); 110 | } 111 | 112 | /** 113 | * Reads a single line of data from the stream. 114 | * 115 | * @param string $token 116 | * @throws Ts3Exception 117 | * @return StringHelper 118 | */ 119 | public function readLine($token = "\n") 120 | { 121 | $this->connect(); 122 | 123 | $line = StringHelper::factory(""); 124 | 125 | while (!$line->endsWith($token)) { 126 | $this->waitForReadyRead(); 127 | 128 | $data = @fgets($this->stream, 4096); 129 | 130 | Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataRead", $data); 131 | 132 | if ($data === false) { 133 | if ($line->count()) { 134 | $line->append($token); 135 | } else { 136 | throw new Ts3Exception( 137 | "connection to server '" . $this->config["host"] . ":" . $this->config["port"] . "' lost" 138 | ); 139 | } 140 | } else { 141 | $line->append($data); 142 | } 143 | } 144 | 145 | return $line->trim(); 146 | } 147 | 148 | /** 149 | * Writes data to the stream. 150 | * 151 | * @param string $data 152 | * @return void 153 | */ 154 | public function send($data) 155 | { 156 | $this->connect(); 157 | 158 | @stream_socket_sendto($this->stream, $data); 159 | 160 | Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataSend", $data); 161 | } 162 | 163 | /** 164 | * Writes a line of data to the stream. 165 | * 166 | * @param string $data 167 | * @param string $separator 168 | * @return void 169 | */ 170 | public function sendLine($data, $separator = "\n") 171 | { 172 | $size = strlen($data); 173 | $pack = 4096; 174 | 175 | for ($seek = 0; $seek < $size;) { 176 | $rest = $size - $seek; 177 | $pack = $rest < $pack ? $rest : $pack; 178 | $buff = substr($data, $seek, $pack); 179 | $seek = $seek + $pack; 180 | 181 | if ($seek >= $size) { 182 | $buff .= $separator; 183 | } 184 | 185 | $this->send($buff); 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /TeamSpeak3/Transport/UDP.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Transport; 29 | 30 | use TeamSpeak3\Helper\Signal; 31 | use TeamSpeak3\Helper\StringHelper; 32 | use TeamSpeak3\Ts3Exception; 33 | 34 | /** 35 | * @class UDP 36 | * @brief Class for connecting to a remote server through UDP. 37 | */ 38 | class UDP extends AbstractTransport 39 | { 40 | /** 41 | * Connects to a remote server. 42 | * 43 | * @throws Ts3Exception 44 | * @return void 45 | */ 46 | public function connect() 47 | { 48 | if ($this->stream !== null) { 49 | return; 50 | } 51 | 52 | $host = strval($this->config["host"]); 53 | $port = strval($this->config["port"]); 54 | 55 | $address = "udp://" . $host . ":" . $port; 56 | $timeout = intval($this->config["timeout"]); 57 | 58 | $this->stream = @stream_socket_client($address, $errno, $errstr, $timeout); 59 | 60 | if ($this->stream === false) { 61 | throw new Ts3Exception( 62 | StringHelper::factory($errstr)->toUtf8()->toString(), 63 | $errno 64 | ); 65 | } 66 | 67 | @stream_set_timeout($this->stream, $timeout); 68 | @stream_set_blocking($this->stream, $this->config["blocking"] ? 1 : 0); 69 | } 70 | 71 | /** 72 | * Disconnects from a remote server. 73 | * 74 | * @return void 75 | */ 76 | public function disconnect() 77 | { 78 | if ($this->stream === null) { 79 | return; 80 | } 81 | 82 | $this->stream = null; 83 | 84 | Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "Disconnected"); 85 | } 86 | 87 | /** 88 | * Reads data from the stream. 89 | * 90 | * @param integer $length 91 | * @throws Ts3Exception 92 | * @return StringHelper 93 | */ 94 | public function read($length = 4096) 95 | { 96 | $this->connect(); 97 | $this->waitForReadyRead(); 98 | 99 | $data = @fread($this->stream, $length); 100 | 101 | Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataRead", $data); 102 | 103 | if ($data === false) { 104 | throw new Ts3Exception( 105 | "connection to server '" . $this->config["host"] . ":" . $this->config["port"] . "' lost" 106 | ); 107 | } 108 | 109 | return new StringHelper($data); 110 | } 111 | 112 | /** 113 | * Writes data to the stream. 114 | * 115 | * @param string $data 116 | * @return void 117 | */ 118 | public function send($data) 119 | { 120 | $this->connect(); 121 | 122 | @stream_socket_sendto($this->stream, $data); 123 | 124 | Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataSend", $data); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /TeamSpeak3/Ts3Exception.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3; 29 | 30 | use TeamSpeak3\Helper\Signal; 31 | use TeamSpeak3\Helper\StringHelper; 32 | 33 | 34 | /** 35 | * @class Ts3Exception 36 | * @brief Enhanced exception class for TeamSpeak3 objects. 37 | */ 38 | class Ts3Exception extends \Exception 39 | { 40 | /** 41 | * Stores custom error messages. 42 | * 43 | * @var array 44 | */ 45 | protected static $messages = array(); 46 | 47 | /** 48 | * The Ts3Exception constructor. 49 | * 50 | * @param string $mesg 51 | * @param integer $code 52 | * @return Ts3Exception 53 | */ 54 | public function __construct($mesg, $code = 0x00) 55 | { 56 | parent::__construct($mesg, $code); 57 | 58 | if (array_key_exists((int)$code, self::$messages)) { 59 | $this->message = $this->prepareCustomMessage(self::$messages[intval($code)]); 60 | } 61 | 62 | Signal::getInstance()->emit("errorException", $this); 63 | } 64 | 65 | /** 66 | * Prepares a custom error message by replacing pre-defined signs with given values. 67 | * 68 | * @param \Teamspeak3\Helper\StringHelper $mesg 69 | * @return \Teamspeak3\Helper\StringHelper 70 | */ 71 | protected function prepareCustomMessage(StringHelper $mesg) 72 | { 73 | $args = array( 74 | "code" => $this->getCode(), 75 | "mesg" => $this->getMessage(), 76 | "line" => $this->getLine(), 77 | "file" => $this->getFile(), 78 | ); 79 | 80 | return $mesg->arg($args)->toString(); 81 | } 82 | 83 | /** 84 | * Registers a custom error message to $code. 85 | * 86 | * @param integer $code 87 | * @param string $mesg 88 | * @throws Ts3Exception 89 | * @return void 90 | */ 91 | public static function registerCustomMessage($code, $mesg) 92 | { 93 | if (array_key_exists((int)$code, self::$messages)) { 94 | throw new self("custom message for code 0x" . strtoupper(dechex($code)) . " is already registered"); 95 | } 96 | 97 | if (!is_string($mesg)) { 98 | throw new self("custom message for code 0x" . strtoupper(dechex($code)) . " must be a string"); 99 | } 100 | 101 | self::$messages[(int)$code] = new StringHelper($mesg); 102 | } 103 | 104 | /** 105 | * Unregisters a custom error message from $code. 106 | * 107 | * @param integer $code 108 | * @throws Ts3Exception 109 | * @return void 110 | */ 111 | public static function unregisterCustomMessage($code) 112 | { 113 | if (!array_key_exists((int)$code, self::$messages)) { 114 | throw new self("custom message for code 0x" . strtoupper(dechex($code)) . " is not registered"); 115 | } 116 | 117 | unset(self::$messages[intval($code)]); 118 | } 119 | 120 | /** 121 | * Returns the class from which the exception was thrown. 122 | * 123 | * @return string 124 | */ 125 | public function getSender() 126 | { 127 | $trace = $this->getTrace(); 128 | 129 | return (isset($trace[0]["class"])) ? $trace[0]["class"] : "{main}"; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /TeamSpeak3/Viewer/IViewer.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Viewer; 29 | 30 | use TeamSpeak3\Node\AbstractNode; 31 | 32 | /** 33 | * @class IViewer 34 | * @brief Interface class describing a TeamSpeak 3 viewer. 35 | */ 36 | interface IViewer 37 | { 38 | /** 39 | * Returns the code needed to display a node in a TeamSpeak 3 viewer. 40 | * 41 | * @param AbstractNode $node 42 | * @param array $siblings 43 | * @return string 44 | */ 45 | public function fetchObject(AbstractNode $node, array $siblings = array()); 46 | } 47 | -------------------------------------------------------------------------------- /TeamSpeak3/Viewer/Text.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @package TeamSpeak3 23 | * @version 1.1.23 24 | * @author Sven 'ScP' Paulsen 25 | * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. 26 | */ 27 | 28 | namespace TeamSpeak3\Viewer; 29 | 30 | use TeamSpeak3\Helper\StringHelper; 31 | use TeamSpeak3\Node\AbstractNode; 32 | 33 | /** 34 | * @class Text 35 | * @brief Renders nodes used in ASCII-based TeamSpeak 3 viewers. 36 | */ 37 | class Text implements IViewer 38 | { 39 | /** 40 | * A pre-defined pattern used to display a node in a TeamSpeak 3 viewer. 41 | * 42 | * @var string 43 | */ 44 | protected $pattern = "%0%1 %2\n"; 45 | 46 | /** 47 | * Returns the code needed to display a node in a TeamSpeak 3 viewer. 48 | * 49 | * @param AbstractNode $node 50 | * @param array $siblings 51 | * @return StringHelper 52 | */ 53 | public function fetchObject(AbstractNode $node, array $siblings = array()) 54 | { 55 | $this->currObj = $node; 56 | $this->currSib = $siblings; 57 | 58 | $args = array( 59 | $this->getPrefix(), 60 | $this->getCorpusIcon(), 61 | $this->getCorpusName(), 62 | ); 63 | 64 | return StringHelper::factory($this->pattern)->arg($args); 65 | } 66 | 67 | /** 68 | * Returns the ASCII string to display the prefix of the current node. 69 | * 70 | * @return string 71 | */ 72 | protected function getPrefix() 73 | { 74 | $prefix = ""; 75 | 76 | if (count($this->currSib)) { 77 | $last = array_pop($this->currSib); 78 | 79 | foreach ($this->currSib as $sibling) { 80 | $prefix .= ($sibling) ? "| " : " "; 81 | } 82 | 83 | $prefix .= ($last) ? "\\-" : "|-"; 84 | } 85 | 86 | return $prefix; 87 | } 88 | 89 | /** 90 | * Returns an ASCII string which can be used to display the status icon for a 91 | * AbstractNode object. 92 | * 93 | * @return string 94 | */ 95 | protected function getCorpusIcon() 96 | { 97 | return $this->currObj->getSymbol(); 98 | } 99 | 100 | /** 101 | * Returns a string for the current corpus element which contains the display name 102 | * for the current AbstractNode object. 103 | * 104 | * @return string 105 | */ 106 | protected function getCorpusName() 107 | { 108 | return $this->currObj; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fkubis/teamspeak-php-framework", 3 | "type": "library", 4 | "description": "Clone of TS3 PHP Framework 1.1.23 providing the library as composer project.", 5 | "keywords": ["teamspeak3"], 6 | "minimum-stability": "dev", 7 | "homepage": "https://github.com/fkubis/teamspeak-php-framework", 8 | "license": "GPL2", 9 | "authors": [ 10 | { 11 | "name": "Sven Paulsen" 12 | }, 13 | { 14 | "name": "Frank Kubis", 15 | "email": "f.kubis@aranox.de" 16 | } 17 | ], 18 | "autoload": { 19 | "psr-4": { "TeamSpeak3\\": "TeamSpeak3/" } 20 | }, 21 | "require": { 22 | "php": ">=5.3.3" 23 | } 24 | } --------------------------------------------------------------------------------