diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..caba276 --- /dev/null +++ b/.gitignore @@ -0,0 +1,66 @@ +config/config.php +prototypes/ + +# Created by https://www.gitignore.io/api/windows,osx,linux + +### Windows ### +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* \ No newline at end of file diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..62a4124 --- /dev/null +++ b/.htaccess @@ -0,0 +1,43 @@ +# (c) 2015-2016 Wruczek + +AddDefaultCharset UTF-8 + +# DISABLE DIRECTORY LISTING +Options -Indexes + +ErrorDocument 403 " 403 - brak dostępu

403 brak dostępu

Nie posiadasz uprawnień do przeglądania tej strony.


←   Powrót
" + +ErrorDocument 404 " 404 - nie znaleziono

404 strony nie znaleziono

Strona której szukasz nie została odnaleziona.


←   Powrót
" + +ErrorDocument 500 " 500 - błąd serwera

500 błąd serwera

Wystąpił błąd serwera. Spróbuj ponownie później.


←   Powrót
" + + + + +RewriteEngine On + +# REDIRECTING FROM lol.com/page.php or lol.com/page.html to lol.com/page +RewriteCond %{THE_REQUEST} \ /(.+)\.php +RewriteRule ^ /%1 [L,R=301] +RewriteCond %{THE_REQUEST} \ /(.+)\.html +RewriteRule ^ /%1 [L,R=301] + +# PAGES WITHOUT .PHP AT THE END +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME}\.php -f +RewriteRule ^(.*)$ $1.php + +# PAGES WITHOUT .HTML AT THE END +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME}\.html -f +RewriteRule ^(.*)$ $1.html + + + +# Enable GZIP + +AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript +BrowserMatch ^Mozilla/4 gzip-only-text/html +BrowserMatch ^Mozilla/4\.0[678] no-gzip +BrowserMatch \bMSIE !no-gzip !gzip-only-text/html + diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..b227051 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Wruczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e37bf0 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# ts-website \ No newline at end of file diff --git a/api/status.php b/api/status.php new file mode 100644 index 0000000..2d4ffb6 --- /dev/null +++ b/api/status.php @@ -0,0 +1,83 @@ +get('serverstatus'); + +// $cache->clean(); + +if (is_null($serverstatus)) { + $serverstatus = getResult(); + $cache->set('serverstatus', $serverstatus, 10); +} + +die ($serverstatus); + +// ********* +// METHODS +// ********* + +function getResult() { + try { + $start = microtime(true); + + $tsstatus = getTeamspeakServerStatus(); + + $stop = microtime(true); + + return json_encode(array( + "tsstatus" => $tsstatus, + "generated" => date('d-m-Y H:i:s') + )); + } catch (Exception $e) { + scriptFail($e); + } +} + +function scriptFail($error) { + die(json_encode(array( + "success" => false, + "id" => "script_error", + "message" => "There has been an error while retrieving the server status" + ,"error" => $error + ))); +} + +function exception_error_handler($errno, $errstr, $errfile, $errline ) { + scriptFail("[$errfile @ $errline] " . $errstr); +} + +function getTeamspeakServerStatus() { + + $response = pingTeamspeakServerFromConfig(); + + if ($response) { + return array( + "success" => $response["virtualserver_status"]->toString() == "online", + "name" => $response["virtualserver_name"]->toString(), + "clientsonline" => $response["virtualserver_clientsonline"] - $response["virtualserver_queryclientsonline"], + "maxclients" => $response["virtualserver_maxclients"], + "version" => TeamSpeak3_Helper_Convert::versionShort($response["virtualserver_version"]->toString())->toString(), + "platform" => $response["virtualserver_platform"]->toString(), + "uptime" => TeamSpeak3_Helper_Convert::seconds($response["virtualserver_uptime"], false, "%dd %02dh %02dm"), + "averagePacketloss" => $response["virtualserver_total_packetloss_total"]->toString(), + "averagePing" => $response["virtualserver_total_ping"]->toString() + ); + } else { + return array( + "success" => false, + "id" => "not_responding", + "message" => "Server is not responding" + ); + } +} diff --git a/bans.php b/bans.php new file mode 100644 index 0000000..8be13be --- /dev/null +++ b/bans.php @@ -0,0 +1,105 @@ +get('banlist'); + +// $cache->clean(); + +if (is_null($banlist)) { + $banlist = array(getBanlist(), date('d-m-Y H:i:s')); + $cache->set('banlist', $banlist, 60); +} + + +?> + +
+
+

Lista banów

+
+
+ + +
+

BRAK ZBANOWANYCH UŻYTKOWNIKÓW

+
+ +
+ + + + + + + + + + + + + +
NickPowódZbanowany przezData zbanowaniaWygasa
+
+ + +
+ +
+ +banList(); + + $output = ""; + + foreach ($bany as $ban) { + + if(!isset($ban['lastnickname'])) + continue; + + $lastnickname = $ban['lastnickname']->toString(); + $reason = $ban['reason']->toString(); + $invokername = $ban['invokername']->toString(); + $created = date('d-m-Y H:i:s', $ban['created']); + $duration = $ban['duration']; + + if($duration == 0) + $expires = "Ban permanentny"; + else + $expires = date('d-m-Y H:i:s', $ban['created'] + $duration); + + $output .= "$lastnickname$reason$invokername$created$expires"; + } + + return $output; + } catch(TeamSpeak3_Exception $e) { + if($e->getCode() == 1281) { + return false; + } else { + return '

Wystąpił błąd ' . $e->getCode() . ': ' . $e->getMessage() . '

'; + } + } + +} + + +require_once __DIR__ . "/include/footer.php"; +?> diff --git a/config/config.template.php b/config/config.template.php new file mode 100644 index 0000000..93e86bd --- /dev/null +++ b/config/config.template.php @@ -0,0 +1,46 @@ + .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} + +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} + +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} + +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} + +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} + +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} + +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} + +.navbar-brand { + float: left; + padding: 19.5px 15px; + font-size: 19px; + line-height: 21px; + height: 60px; +} + +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} + +.navbar-brand > img { + display: block; +} + +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} + +.navbar-toggle { + position: relative; + float: right; + margin-right: 15px; + padding: 9px 10px; + margin-top: 13px; + margin-bottom: 0px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} + +.navbar-toggle:focus { + outline: 0; +} + +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} + +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} + +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} + +.navbar-nav { + margin: 9.75px -15px; +} + +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 21px; +} + +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + + .navbar-nav .open .dropdown-menu > li > a { + line-height: 21px; + } + + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} + +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + + .navbar-nav > li { + float: left; + } + + .navbar-nav > li > a { + padding-top: 19.5px; + padding-bottom: 19.5px; + } +} + +.navbar-form { + margin-left: -15px; + margin-right: -15px; + padding: 10px 15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + margin-top: 7.5px; + margin-bottom: 7.5px; +} + +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + + .navbar-form .form-control-static { + display: inline-block; + } + + .navbar-form .input-group { + display: inline-table; + vertical-align: middle; + } + + .navbar-form .input-group .input-group-addon, + .navbar-form .input-group .input-group-btn, + .navbar-form .input-group .form-control { + width: auto; + } + + .navbar-form .input-group > .form-control { + width: 100%; + } + + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} + +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } + + .navbar-form .form-group:last-child { + margin-bottom: 0; + } +} + +@media (min-width: 768px) { + .navbar-form { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} + +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + margin-bottom: 0; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.navbar-btn { + margin-top: 7.5px; + margin-bottom: 7.5px; +} + +.navbar-btn.btn-sm { + margin-top: 12.5px; + margin-bottom: 12.5px; +} + +.navbar-btn.btn-xs { + margin-top: 19px; + margin-bottom: 19px; +} + +.navbar-text { + margin-top: 19.5px; + margin-bottom: 19.5px; +} + +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-left: 15px; + margin-right: 15px; + } +} + +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + + .navbar-right { + float: right !important; + margin-right: -15px; + } + + .navbar-right ~ .navbar-right { + margin-right: 0; + } +} diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..ad31e97 --- /dev/null +++ b/css/style.css @@ -0,0 +1,100 @@ +.fa { + margin-right: 5px; +} + +.icon-smaller { + font-size: 0.7em; +} + +a { + -webkit-transition: color 500ms ease-out; + -moz-transition: color 500ms ease-out; + -o-transition: color 500ms ease-out; + transition: color 500ms ease-out; +} + +.news-header { + font-size: 1.4em; + text-align: center; +} + +.news-author { + font-size: 0.7em; + text-align: right; +} + +.pullright { + float: right +} + +/* ****** */ +/* STATUS */ +/* ****** */ + +.serverstatus p { + margin: 0px +} + +.serverstatus a { + float: right +} + +.serverstatus span { + float: right +} + +/* ********* */ +/* ADMINLIST */ +/* ********* */ + +.adminlist > .groupname ~ .groupname { + margin-top: 15px; +} + +.adminlist .groupname { + text-align: center; + font-size: 1.2em; + border-bottom: 1px solid #677481; + margin-bottom: 5px; +} + +.adminlist .label-primary { + background-color: #375a7f; +} + +.adminlist p { + margin: 0px +} + +.adminlist img { + margin-right: 3px +} + +.adminlist .iconspacer { + margin-left: 19px +} + + +/* ****** */ +/* NAVBAR */ +/* ****** */ + +body { + padding-top: 80px; +} + +.navbar { + font-size: initial; +} + +.navbar-brand { + padding: 0px 10px 0px 0px; + display: flex; + align-items: center; +} + +.navbar-brand > img { + height: 100%; + padding: 10px 5px 10px 15px; + width: auto; +} diff --git a/include/adminlist.php b/include/adminlist.php new file mode 100644 index 0000000..8ee636d --- /dev/null +++ b/include/adminlist.php @@ -0,0 +1,74 @@ +get('adminlist'); + +// $cache->clean(); + +if (is_null($adminlist)) { + $adminlist = array(getAdminList(), date('d-m-Y H:i:s')); + $cache->set('adminlist', $adminlist, 30); +} + +// FUNCTIONS + +function getAdminList() { + + try { + $tsAdmin = TeamSpeak3::factory(getTeamspeakURI(). "#no_query_clients"); + $serverGroupList = $tsAdmin->serverGroupList(); + + $output = ""; + + foreach ($serverGroupList as $group) { + + if(!isAdminGroup($group->getId())) + continue; + + $output .= "

$group

"; + + foreach ($group->clientList() as $userInfo) { + $user = getClientByDbid($tsAdmin, $userInfo['cldbid']); + + if(!$user) { + $output .= '

' . $userInfo['client_nickname'] . 'Offline

'; + continue; + } + + $output .= '

' . '' . '' . $user . '' . ($user['client_away'] ? 'Away' : 'Online') . '

'; + } + } + + return $output; + } catch(TeamSpeak3_Exception $e) { + return '

Wystąpił błąd ' . $e->getCode() . ': ' . $e->getMessage() . '

'; + } + +} + +function isAdminGroup($groupid) { + global $config; + $admingroups = $config["adminlist"]; + + return in_array($groupid, $admingroups); +} + +function getClientByDbid($tsAdmin, $cldbid) { + try { + return $tsAdmin->clientGetByDbid($cldbid); + } catch(TeamSpeak3_Exception $e) { + return false; + } +} + +// echo getAdminList(); diff --git a/include/configcheck.php b/include/configcheck.php new file mode 100644 index 0000000..9621253 --- /dev/null +++ b/include/configcheck.php @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + BŁĄD: Brak pliku config.php + + + + + + + + + + + + + +
+ +
+
+

Brak pliku config.php

+
+
+

Przejdź do folderu config i zmień nazwę pliku z config.template.php na config.php.

+

Skonfiguruj stronę według własnych potrzeb.

+
+
+ +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", $creationtime); +?> diff --git a/include/header.php b/include/header.php new file mode 100644 index 0000000..194c08b --- /dev/null +++ b/include/header.php @@ -0,0 +1,130 @@ + + + + + + + + + + "> + + + <?php echo $config["general"]["title"] . $config["general"]["subtitle"]; ?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
Status serwera
+
+
+

Adres:

+
+
+ + Ładowanie... +
+
+
+
+
+ + +
+
Status administracji
+
+ +
+
+ +
+
Podgląd serwera
+ +
+
+ +
\ No newline at end of file diff --git a/include/modulecheck.php b/include/modulecheck.php new file mode 100644 index 0000000..23e6b6e --- /dev/null +++ b/include/modulecheck.php @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + BŁĄD: Brak wymaganych rozszerzeń + + + + + + + + + + + + + +
+ +
+
+

Brak wymaganych rozszerzeń

+
+
+

Na swoim serwerze nie posiadasz modułu rewrite wymaganego do poprawnego działania tej strony.

+

Posiadasz system Ubuntu? Świetnie! Uruchom poniższe komendy, by włączyć wymagany moduł:

+
sudo a2enmod rewrite
+sudo service apache2 reload
+

Używasz system Debian? Uruchom owe komendy pomijając przedrostek sudo:

+
a2enmod rewrite
+service apache2 reload
+

Jeśli używasz hostingu i nie masz dostępu do konsoli, skontaktuj się z administratorem lub pomocą techniczną Twojego hostingu.

+
+
+ +
+ + + + + +getProperty("virtualserver_status")) + throw new Exception("Server is offline"); + + return $tsAdmin->getInfo(); + } catch(TeamSpeak3_Exception $e) { + return false; + } + +} + +function getTeamspeakURI() { + global $config; + $host = $config['teamspeak']['host']; + $login = $config['teamspeak']['login']; + $passwd = $config['teamspeak']['password']; + $sport = $config['teamspeak']['server_port']; + $qport = $config['teamspeak']['query_port']; + return "serverquery://$login:$passwd@$host:$qport/?server_port=$sport"; +} diff --git a/js/bans.js b/js/bans.js new file mode 100644 index 0000000..f771279 --- /dev/null +++ b/js/bans.js @@ -0,0 +1,8 @@ +$(document).ready(function () { + $('#banlist').dataTable({ + "order": [], + "language": { + "url": "//cdn.datatables.net/plug-ins/1.10.12/i18n/Polish.json" + } + }); +}); diff --git a/js/script.js b/js/script.js new file mode 100644 index 0000000..2231d46 --- /dev/null +++ b/js/script.js @@ -0,0 +1,10 @@ +$(function () { + $('[data-toggle="tooltip"]').tooltip({"html": true}) +}) + +$('.news-body').readmore({ + speed: 500, + collapsedHeight: 300, + moreLink: '', + lessLink: '' +}); diff --git a/js/status.js b/js/status.js new file mode 100644 index 0000000..1e58759 --- /dev/null +++ b/js/status.js @@ -0,0 +1,46 @@ +$(document).ready(function () { + + checkStatus(); + + var intervalid = setInterval(function () { + checkStatus(); + }, 10 * 1000); +}) + +function checkStatus() { + + $.ajax({ + url: "api/status", + success: function (json) { + + json = json.tsstatus; + + var result = ""; + + if (json.success) { + var clientsonline = json.clientsonline; + var maxclients = json.maxclients; + var clientsprecent = Math.round(json.clientsonline * 100 / json.maxclients); + var version = json.version; + var platform = json.platform; + var uptime = json.uptime; + var averagePacketloss = Math.round(json.averagePacketloss * 100) / 100; + var averagePing = Math.round(json.averagePing * 100) / 100; + + result = + '

Online: ' + clientsonline + ' / ' + maxclients + ' (' + clientsprecent + '%)

' + + '

Uptime: ' + uptime + '

' + + '

Wersja: ' + version + ' @ ' + platform + '

' + + '

Średni ping: ' + averagePing + ' ms

' + + '

Średni packet loss: ' + averagePacketloss + '%

'; + } else { + result = '

Online: Offline

'; + } + + $("#serverstatus").html(result); + }, + error: function (result) { + $("#serverstatus").html('

Online: ERROR

'); + } + }) +} diff --git a/lib/parsedown/parsedown.php b/lib/parsedown/parsedown.php new file mode 100644 index 0000000..646af86 --- /dev/null +++ b/lib/parsedown/parsedown.php @@ -0,0 +1,1538 @@ +DefinitionData = array(); + + # standardize line breaks + $text = str_replace(array("\r\n", "\r"), "\n", $text); + + # remove surrounding line breaks + $text = trim($text, "\n"); + + # split text into lines + $lines = explode("\n", $text); + + # iterate through lines to identify blocks + $markup = $this->lines($lines); + + # trim line breaks + $markup = trim($markup, "\n"); + + return $markup; + } + + # + # Setters + # + + function setBreaksEnabled($breaksEnabled) + { + $this->breaksEnabled = $breaksEnabled; + + return $this; + } + + protected $breaksEnabled; + + function setMarkupEscaped($markupEscaped) + { + $this->markupEscaped = $markupEscaped; + + return $this; + } + + protected $markupEscaped; + + function setUrlsLinked($urlsLinked) + { + $this->urlsLinked = $urlsLinked; + + return $this; + } + + protected $urlsLinked = true; + + # + # Lines + # + + protected $BlockTypes = array( + '#' => array('Header'), + '*' => array('Rule', 'List'), + '+' => array('List'), + '-' => array('SetextHeader', 'Table', 'Rule', 'List'), + '0' => array('List'), + '1' => array('List'), + '2' => array('List'), + '3' => array('List'), + '4' => array('List'), + '5' => array('List'), + '6' => array('List'), + '7' => array('List'), + '8' => array('List'), + '9' => array('List'), + ':' => array('Table'), + '<' => array('Comment', 'Markup'), + '=' => array('SetextHeader'), + '>' => array('Quote'), + '[' => array('Reference'), + '_' => array('Rule'), + '`' => array('FencedCode'), + '|' => array('Table'), + '~' => array('FencedCode'), + ); + + # ~ + + protected $unmarkedBlockTypes = array( + 'Code', + ); + + # + # Blocks + # + + protected function lines(array $lines) + { + $CurrentBlock = null; + + foreach ($lines as $line) + { + if (chop($line) === '') + { + if (isset($CurrentBlock)) + { + $CurrentBlock['interrupted'] = true; + } + + continue; + } + + if (strpos($line, "\t") !== false) + { + $parts = explode("\t", $line); + + $line = $parts[0]; + + unset($parts[0]); + + foreach ($parts as $part) + { + $shortage = 4 - mb_strlen($line, 'utf-8') % 4; + + $line .= str_repeat(' ', $shortage); + $line .= $part; + } + } + + $indent = 0; + + while (isset($line[$indent]) and $line[$indent] === ' ') + { + $indent ++; + } + + $text = $indent > 0 ? substr($line, $indent) : $line; + + # ~ + + $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); + + # ~ + + if (isset($CurrentBlock['continuable'])) + { + $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); + + if (isset($Block)) + { + $CurrentBlock = $Block; + + continue; + } + else + { + if ($this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + } + } + + # ~ + + $marker = $text[0]; + + # ~ + + $blockTypes = $this->unmarkedBlockTypes; + + if (isset($this->BlockTypes[$marker])) + { + foreach ($this->BlockTypes[$marker] as $blockType) + { + $blockTypes []= $blockType; + } + } + + # + # ~ + + foreach ($blockTypes as $blockType) + { + $Block = $this->{'block'.$blockType}($Line, $CurrentBlock); + + if (isset($Block)) + { + $Block['type'] = $blockType; + + if ( ! isset($Block['identified'])) + { + $Blocks []= $CurrentBlock; + + $Block['identified'] = true; + } + + if ($this->isBlockContinuable($blockType)) + { + $Block['continuable'] = true; + } + + $CurrentBlock = $Block; + + continue 2; + } + } + + # ~ + + if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) + { + $CurrentBlock['element']['text'] .= "\n".$text; + } + else + { + $Blocks []= $CurrentBlock; + + $CurrentBlock = $this->paragraph($Line); + + $CurrentBlock['identified'] = true; + } + } + + # ~ + + if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + + # ~ + + $Blocks []= $CurrentBlock; + + unset($Blocks[0]); + + # ~ + + $markup = ''; + + foreach ($Blocks as $Block) + { + if (isset($Block['hidden'])) + { + continue; + } + + $markup .= "\n"; + $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']); + } + + $markup .= "\n"; + + # ~ + + return $markup; + } + + protected function isBlockContinuable($Type) + { + return method_exists($this, 'block'.$Type.'Continue'); + } + + protected function isBlockCompletable($Type) + { + return method_exists($this, 'block'.$Type.'Complete'); + } + + # + # Code + + protected function blockCode($Line, $Block = null) + { + if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted'])) + { + return; + } + + if ($Line['indent'] >= 4) + { + $text = substr($Line['body'], 4); + + $Block = array( + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => array( + 'name' => 'code', + 'text' => $text, + ), + ), + ); + + return $Block; + } + } + + protected function blockCodeContinue($Line, $Block) + { + if ($Line['indent'] >= 4) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['element']['text']['text'] .= "\n"; + + $text = substr($Line['body'], 4); + + $Block['element']['text']['text'] .= $text; + + return $Block; + } + } + + protected function blockCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Comment + + protected function blockComment($Line) + { + if ($this->markupEscaped) + { + return; + } + + if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') + { + $Block = array( + 'markup' => $Line['body'], + ); + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + } + + protected function blockCommentContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + $Block['markup'] .= "\n" . $Line['body']; + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + + # + # Fenced Code + + protected function blockFencedCode($Line) + { + if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches)) + { + $Element = array( + 'name' => 'code', + 'text' => '', + ); + + if (isset($matches[1])) + { + $class = 'language-'.$matches[1]; + + $Element['attributes'] = array( + 'class' => $class, + ); + } + + $Block = array( + 'char' => $Line['text'][0], + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => $Element, + ), + ); + + return $Block; + } + } + + protected function blockFencedCodeContinue($Line, $Block) + { + if (isset($Block['complete'])) + { + return; + } + + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) + { + $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); + + $Block['complete'] = true; + + return $Block; + } + + $Block['element']['text']['text'] .= "\n".$Line['body'];; + + return $Block; + } + + protected function blockFencedCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Header + + protected function blockHeader($Line) + { + if (isset($Line['text'][1])) + { + $level = 1; + + while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') + { + $level ++; + } + + if ($level > 6) + { + return; + } + + $text = trim($Line['text'], '# '); + + $Block = array( + 'element' => array( + 'name' => 'h' . min(6, $level), + 'text' => $text, + 'handler' => 'line', + ), + ); + + return $Block; + } + } + + # + # List + + protected function blockList($Line) + { + list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); + + if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'indent' => $Line['indent'], + 'pattern' => $pattern, + 'element' => array( + 'name' => $name, + 'handler' => 'elements', + ), + ); + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $matches[2], + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + } + + protected function blockListContinue($Line, array $Block) + { + if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['li']['text'] []= ''; + + unset($Block['interrupted']); + } + + unset($Block['li']); + + $text = isset($matches[1]) ? $matches[1] : ''; + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $text, + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + + if ($Line['text'][0] === '[' and $this->blockReference($Line)) + { + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + return $Block; + } + + if ($Line['indent'] > 0) + { + $Block['li']['text'] []= ''; + + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + unset($Block['interrupted']); + + return $Block; + } + } + + # + # Quote + + protected function blockQuote($Line) + { + if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'element' => array( + 'name' => 'blockquote', + 'handler' => 'lines', + 'text' => (array) $matches[1], + ), + ); + + return $Block; + } + } + + protected function blockQuoteContinue($Line, array $Block) + { + if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text'] []= ''; + + unset($Block['interrupted']); + } + + $Block['element']['text'] []= $matches[1]; + + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $Block['element']['text'] []= $Line['text']; + + return $Block; + } + } + + # + # Rule + + protected function blockRule($Line) + { + if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) + { + $Block = array( + 'element' => array( + 'name' => 'hr' + ), + ); + + return $Block; + } + } + + # + # Setext + + protected function blockSetextHeader($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (chop($Line['text'], $Line['text'][0]) === '') + { + $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; + + return $Block; + } + } + + # + # Markup + + protected function blockMarkup($Line) + { + if ($this->markupEscaped) + { + return; + } + + if (preg_match('/^<(\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) + { + $element = strtolower($matches[1]); + + if (in_array($element, $this->textLevelElements)) + { + return; + } + + $Block = array( + 'name' => $matches[1], + 'depth' => 0, + 'markup' => $Line['text'], + ); + + $length = strlen($matches[0]); + + $remainder = substr($Line['text'], $length); + + if (trim($remainder) === '') + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + $Block['closed'] = true; + + $Block['void'] = true; + } + } + else + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + return; + } + + if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) + { + $Block['closed'] = true; + } + } + + return $Block; + } + } + + protected function blockMarkupContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open + { + $Block['depth'] ++; + } + + if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close + { + if ($Block['depth'] > 0) + { + $Block['depth'] --; + } + else + { + $Block['closed'] = true; + } + } + + if (isset($Block['interrupted'])) + { + $Block['markup'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['markup'] .= "\n".$Line['body']; + + return $Block; + } + + # + # Reference + + protected function blockReference($Line) + { + if (preg_match('/^\[(.+?)\]:[ ]*?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) + { + $id = strtolower($matches[1]); + + $Data = array( + 'url' => $matches[2], + 'title' => null, + ); + + if (isset($matches[3])) + { + $Data['title'] = $matches[3]; + } + + $this->DefinitionData['Reference'][$id] = $Data; + + $Block = array( + 'hidden' => true, + ); + + return $Block; + } + } + + # + # Table + + protected function blockTable($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') + { + $alignments = array(); + + $divider = $Line['text']; + + $divider = trim($divider); + $divider = trim($divider, '|'); + + $dividerCells = explode('|', $divider); + + foreach ($dividerCells as $dividerCell) + { + $dividerCell = trim($dividerCell); + + if ($dividerCell === '') + { + continue; + } + + $alignment = null; + + if ($dividerCell[0] === ':') + { + $alignment = 'left'; + } + + if (substr($dividerCell, - 1) === ':') + { + $alignment = $alignment === 'left' ? 'center' : 'right'; + } + + $alignments []= $alignment; + } + + # ~ + + $HeaderElements = array(); + + $header = $Block['element']['text']; + + $header = trim($header); + $header = trim($header, '|'); + + $headerCells = explode('|', $header); + + foreach ($headerCells as $index => $headerCell) + { + $headerCell = trim($headerCell); + + $HeaderElement = array( + 'name' => 'th', + 'text' => $headerCell, + 'handler' => 'line', + ); + + if (isset($alignments[$index])) + { + $alignment = $alignments[$index]; + + $HeaderElement['attributes'] = array( + 'style' => 'text-align: '.$alignment.';', + ); + } + + $HeaderElements []= $HeaderElement; + } + + # ~ + + $Block = array( + 'alignments' => $alignments, + 'identified' => true, + 'element' => array( + 'name' => 'table', + 'handler' => 'elements', + ), + ); + + $Block['element']['text'] []= array( + 'name' => 'thead', + 'handler' => 'elements', + ); + + $Block['element']['text'] []= array( + 'name' => 'tbody', + 'handler' => 'elements', + 'text' => array(), + ); + + $Block['element']['text'][0]['text'] []= array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $HeaderElements, + ); + + return $Block; + } + } + + protected function blockTableContinue($Line, array $Block) + { + if (isset($Block['interrupted'])) + { + return; + } + + if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) + { + $Elements = array(); + + $row = $Line['text']; + + $row = trim($row); + $row = trim($row, '|'); + + preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); + + foreach ($matches[0] as $index => $cell) + { + $cell = trim($cell); + + $Element = array( + 'name' => 'td', + 'handler' => 'line', + 'text' => $cell, + ); + + if (isset($Block['alignments'][$index])) + { + $Element['attributes'] = array( + 'style' => 'text-align: '.$Block['alignments'][$index].';', + ); + } + + $Elements []= $Element; + } + + $Element = array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $Elements, + ); + + $Block['element']['text'][1]['text'] []= $Element; + + return $Block; + } + } + + # + # ~ + # + + protected function paragraph($Line) + { + $Block = array( + 'element' => array( + 'name' => 'p', + 'text' => $Line['text'], + 'handler' => 'line', + ), + ); + + return $Block; + } + + # + # Inline Elements + # + + protected $InlineTypes = array( + '"' => array('SpecialCharacter'), + '!' => array('Image'), + '&' => array('SpecialCharacter'), + '*' => array('Emphasis'), + ':' => array('Url'), + '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), + '>' => array('SpecialCharacter'), + '[' => array('Link'), + '_' => array('Emphasis'), + '`' => array('Code'), + '~' => array('Strikethrough'), + '\\' => array('EscapeSequence'), + ); + + # ~ + + protected $inlineMarkerList = '!"*_&[:<>`~\\'; + + # + # ~ + # + + public function line($text) + { + $markup = ''; + + # $excerpt is based on the first occurrence of a marker + + while ($excerpt = strpbrk($text, $this->inlineMarkerList)) + { + $marker = $excerpt[0]; + + $markerPosition = strpos($text, $marker); + + $Excerpt = array('text' => $excerpt, 'context' => $text); + + foreach ($this->InlineTypes[$marker] as $inlineType) + { + $Inline = $this->{'inline'.$inlineType}($Excerpt); + + if ( ! isset($Inline)) + { + continue; + } + + # makes sure that the inline belongs to "our" marker + + if (isset($Inline['position']) and $Inline['position'] > $markerPosition) + { + continue; + } + + # sets a default inline position + + if ( ! isset($Inline['position'])) + { + $Inline['position'] = $markerPosition; + } + + # the text that comes before the inline + $unmarkedText = substr($text, 0, $Inline['position']); + + # compile the unmarked text + $markup .= $this->unmarkedText($unmarkedText); + + # compile the inline + $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); + + # remove the examined text + $text = substr($text, $Inline['position'] + $Inline['extent']); + + continue 2; + } + + # the marker does not belong to an inline + + $unmarkedText = substr($text, 0, $markerPosition + 1); + + $markup .= $this->unmarkedText($unmarkedText); + + $text = substr($text, $markerPosition + 1); + } + + $markup .= $this->unmarkedText($text); + + return $markup; + } + + # + # ~ + # + + protected function inlineCode($Excerpt) + { + $marker = $Excerpt['text'][0]; + + if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(? strlen($matches[0]), + 'element' => array( + 'name' => 'code', + 'text' => $text, + ), + ); + } + } + + protected function inlineEmailTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches)) + { + $url = $matches[1]; + + if ( ! isset($matches[2])) + { + $url = 'mailto:' . $url; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $matches[1], + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + protected function inlineEmphasis($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + $marker = $Excerpt['text'][0]; + + if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'strong'; + } + elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'em'; + } + else + { + return; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => $emphasis, + 'handler' => 'line', + 'text' => $matches[1], + ), + ); + } + + protected function inlineEscapeSequence($Excerpt) + { + if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) + { + return array( + 'markup' => $Excerpt['text'][1], + 'extent' => 2, + ); + } + } + + protected function inlineImage($Excerpt) + { + if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') + { + return; + } + + $Excerpt['text']= substr($Excerpt['text'], 1); + + $Link = $this->inlineLink($Excerpt); + + if ($Link === null) + { + return; + } + + $Inline = array( + 'extent' => $Link['extent'] + 1, + 'element' => array( + 'name' => 'img', + 'attributes' => array( + 'src' => $Link['element']['attributes']['href'], + 'alt' => $Link['element']['text'], + ), + ), + ); + + $Inline['element']['attributes'] += $Link['element']['attributes']; + + unset($Inline['element']['attributes']['href']); + + return $Inline; + } + + protected function inlineLink($Excerpt) + { + $Element = array( + 'name' => 'a', + 'handler' => 'line', + 'text' => null, + 'attributes' => array( + 'href' => null, + 'title' => null, + ), + ); + + $extent = 0; + + $remainder = $Excerpt['text']; + + if (preg_match('/\[((?:[^][]|(?R))*)\]/', $remainder, $matches)) + { + $Element['text'] = $matches[1]; + + $extent += strlen($matches[0]); + + $remainder = substr($remainder, $extent); + } + else + { + return; + } + + if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches)) + { + $Element['attributes']['href'] = $matches[1]; + + if (isset($matches[2])) + { + $Element['attributes']['title'] = substr($matches[2], 1, - 1); + } + + $extent += strlen($matches[0]); + } + else + { + if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) + { + $definition = strlen($matches[1]) ? $matches[1] : $Element['text']; + $definition = strtolower($definition); + + $extent += strlen($matches[0]); + } + else + { + $definition = strtolower($Element['text']); + } + + if ( ! isset($this->DefinitionData['Reference'][$definition])) + { + return; + } + + $Definition = $this->DefinitionData['Reference'][$definition]; + + $Element['attributes']['href'] = $Definition['url']; + $Element['attributes']['title'] = $Definition['title']; + } + + $Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']); + + return array( + 'extent' => $extent, + 'element' => $Element, + ); + } + + protected function inlineMarkup($Excerpt) + { + if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false) + { + return; + } + + if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w*[ ]*>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + } + + protected function inlineSpecialCharacter($Excerpt) + { + if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) + { + return array( + 'markup' => '&', + 'extent' => 1, + ); + } + + $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); + + if (isset($SpecialCharacter[$Excerpt['text'][0]])) + { + return array( + 'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', + 'extent' => 1, + ); + } + } + + protected function inlineStrikethrough($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) + { + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'del', + 'text' => $matches[1], + 'handler' => 'line', + ), + ); + } + } + + protected function inlineUrl($Excerpt) + { + if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') + { + return; + } + + if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) + { + $Inline = array( + 'extent' => strlen($matches[0][0]), + 'position' => $matches[0][1], + 'element' => array( + 'name' => 'a', + 'text' => $matches[0][0], + 'attributes' => array( + 'href' => $matches[0][0], + ), + ), + ); + + return $Inline; + } + } + + protected function inlineUrlTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) + { + $url = str_replace(array('&', '<'), array('&', '<'), $matches[1]); + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + # ~ + + protected function unmarkedText($text) + { + if ($this->breaksEnabled) + { + $text = preg_replace('/[ ]*\n/', "
\n", $text); + } + else + { + $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "
\n", $text); + $text = str_replace(" \n", "\n", $text); + } + + return $text; + } + + # + # Handlers + # + + protected function element(array $Element) + { + $markup = '<'.$Element['name']; + + if (isset($Element['attributes'])) + { + foreach ($Element['attributes'] as $name => $value) + { + if ($value === null) + { + continue; + } + + $markup .= ' '.$name.'="'.$value.'"'; + } + } + + if (isset($Element['text'])) + { + $markup .= '>'; + + if (isset($Element['handler'])) + { + $markup .= $this->{$Element['handler']}($Element['text']); + } + else + { + $markup .= $Element['text']; + } + + $markup .= ''; + } + else + { + $markup .= ' />'; + } + + return $markup; + } + + protected function elements(array $Elements) + { + $markup = ''; + + foreach ($Elements as $Element) + { + $markup .= "\n" . $this->element($Element); + } + + $markup .= "\n"; + + return $markup; + } + + # ~ + + protected function li($lines) + { + $markup = $this->lines($lines); + + $trimmedMarkup = trim($markup); + + if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '

') + { + $markup = $trimmedMarkup; + $markup = substr($markup, 3); + + $position = strpos($markup, "

"); + + $markup = substr_replace($markup, '', $position, 4); + } + + return $markup; + } + + # + # Deprecated Methods + # + + function parse($text) + { + $markup = $this->text($text); + + return $markup; + } + + # + # Static Methods + # + + static function instance($name = 'default') + { + if (isset(self::$instances[$name])) + { + return self::$instances[$name]; + } + + $instance = new static(); + + self::$instances[$name] = $instance; + + return $instance; + } + + private static $instances = array(); + + # + # Fields + # + + protected $DefinitionData; + + # + # Read-Only + + protected $specialCharacters = array( + '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', + ); + + protected $StrongRegex = array( + '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', + '_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', + ); + + protected $EmRegex = array( + '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', + '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', + ); + + protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; + + protected $voidElements = array( + 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', + ); + + protected $textLevelElements = array( + 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', + 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', + 'i', 'rp', 'del', 'code', 'strike', 'marquee', + 'q', 'rt', 'ins', 'font', 'strong', + 's', 'tt', 'sub', 'mark', + 'u', 'xm', 'sup', 'nobr', + 'var', 'ruby', + 'wbr', 'span', + 'time', + ); +} diff --git a/lib/phpfastcache/autoload.php b/lib/phpfastcache/autoload.php new file mode 100644 index 0000000..b21baf8 --- /dev/null +++ b/lib/phpfastcache/autoload.php @@ -0,0 +1,15 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +require_once __DIR__."/phpFastCache/phpFastCache.php"; \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/.htaccess b/lib/phpfastcache/phpFastCache/.htaccess new file mode 100644 index 0000000..608da1a --- /dev/null +++ b/lib/phpfastcache/phpFastCache/.htaccess @@ -0,0 +1,3 @@ +order deny,allow +deny from all +allow from 127.0.0.1 \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/CacheManager.php b/lib/phpfastcache/phpFastCache/CacheManager.php new file mode 100644 index 0000000..e690d48 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/CacheManager.php @@ -0,0 +1,173 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache; + +use phpFastCache\Core\phpFastCache; +use phpFastCache\Core\DriverAbstract; + +/** + * Class CacheManager + * @package phpFastCache + * + * @method static DriverAbstract Apc() Apc($config = array()) Return a driver "apc" instance + * @method static DriverAbstract Cookie() Cookie($config = array()) Return a driver "cookie" instance + * @method static DriverAbstract Files() Files($config = array()) Return a driver "files" instance + * @method static DriverAbstract Memcache() Memcache($config = array()) Return a driver "memcache" instance + * @method static DriverAbstract Memcached() Memcached($config = array()) Return a driver "memcached" instance + * @method static DriverAbstract Predis() Predis($config = array()) Return a driver "predis" instance + * @method static DriverAbstract Redis() Redis($config = array()) Return a driver "redis" instance + * @method static DriverAbstract Sqlite() Sqlite($config = array()) Return a driver "sqlite" instance + * @method static DriverAbstract Ssdb() Ssdb($config = array()) Return a driver "ssdb" instance + * @method static DriverAbstract Wincache() Wincache($config = array()) Return a driver "wincache" instance + * @method static DriverAbstract Xcache() Xcache($config = array()) Return a driver "xcache" instance + * + */ +class CacheManager +{ + public static $instances = array(); + public static $memory = array(); + public static $hit = array(); + + /** + * @param string $storage + * @param array $config + * @return DriverAbstract + */ + public static function getInstance($storage = 'auto', $config = array()) + { + $storage = strtolower($storage); + if (empty($config)) { + $config = phpFastCache::$config; + } + if (!isset($config[ 'cache_method' ])) { + $config[ 'cache_method' ] = phpFastCache::$config[ 'cache_method' ]; + } + if (!isset($config[ 'limited_memory_each_object' ])) { + $config[ 'limited_memory_each_object' ] = phpFastCache::$config[ 'limited_memory_each_object' ]; + } + if (isset(phpFastCache::$config[ 'overwrite' ]) && !in_array(phpFastCache::$config[ 'overwrite' ], array('auto', ''), true)) { + phpFastCache::$config[ 'storage' ] = phpFastCache::$config[ 'overwrite' ]; + $storage = phpFastCache::$config[ 'overwrite' ]; + } else if (isset(phpFastCache::$config[ 'storage' ]) && !in_array(phpFastCache::$config[ 'storage' ], array('auto', ''), true)) { + $storage = phpFastCache::$config[ 'storage' ]; + } else if (in_array($storage, array('auto', ''), true)) { + $storage = phpFastCache::getAutoClass($config); + } + + // echo $storage."
"; + $instance = md5(serialize($config) . $storage); + if (!isset(self::$instances[ $instance ]) || is_null(self::$instances[ $instance ])) { + $class = '\phpFastCache\Drivers\\' . $storage; + $config[ 'storage' ] = $storage; + $config[ 'instance' ] = $instance; + $config[ 'class' ] = $class; + if (!isset(self::$memory[ $instance ])) { + self::$memory[ $instance ] = array(); + } + + if (!isset(self::$hit[ $instance ])) { + self::$hit[ $instance ] = array( + "class" => $class, + "storage" => $storage, + "data" => array(), + ); + if ($config[ 'cache_method' ] == 4) { + register_shutdown_function('phpFastCache\CacheManager::cleanCachingMethod', null); + } + } + + self::$instances[ $instance ] = new $class($config); + } + + return self::$instances[ $instance ]; + } + + /** + * Setup Method + * @param string $string | traditional(normal), memory (fast), phpfastcache (fastest) + */ + public static function CachingMethod($string = "phpFastCache") + { + $string = strtolower($string); + if (in_array($string, array("normal", "traditional"))) { + phpFastCache::$config[ 'cache_method' ] = 1; + } else if (in_array($string, array("fast", "memory"))) { + phpFastCache::$config[ 'cache_method' ] = 2; + } else if (in_array($string, array("fastest", "phpfastcache"))) { + phpFastCache::$config[ 'cache_method' ] = 3; + } else if (in_array($string, array("superfast", "phpfastcachex"))) { + phpFastCache::$config[ 'cache_method' ] = 4; + } + } + + /** + * CacheManager::Files(); + * CacheManager::Memcached(); + * CacheManager::get($keyword); + * CacheManager::set(), touch, other @method supported + */ + public static function __callStatic($name, $arguments) + { + $driver = strtolower($name); + if (!isset(self::$instances[ 'loaded' ][ $driver ]) && class_exists("\\phpFastCache\\Drivers\\{$driver}")) { + self::$instances[ 'loaded' ][ $driver ] = true; + } + if (isset(self::$instances[ 'loaded' ][ $driver ])) { + return self::getInstance($name, (isset($arguments[ 0 ]) ? $arguments[ 0 ] : array())); + } else { + return call_user_func_array(array(self::getInstance(), $name), $arguments); + } + + } + + /** + * Shortcut to phpFastCache::setup() + */ + public static function setup($name, $value = '') + { + phpFastCache::setup($name, $value); + } + + /** + * @param string $instance + */ + public static function cleanCachingMethod($instance = null) + { + if (is_null($instance)) { + foreach (self::$instances as $instance => $data) { + self::__CleanCachingMethod($instance); + unset($data); + } + } else { + self::__CleanCachingMethod($instance); + } + } + + /** + * @param string $instance + */ + protected static function __CleanCachingMethod($instance) + { + if(is_array(self::$memory[ $instance ]) && !empty(self::$memory[ $instance ])) { + $old = self::$instances[$instance]->config['cache_method']; + self::$instances[$instance]->config['cache_method'] = 1; + foreach (self::$memory[$instance] as $keyword => $object) { + self::$instances[$instance]->set($keyword, $object['value'], $object['expired_in']); + } + self::$instances[$instance]->config['cache_method'] = $old; + self::$memory[$instance] = array(); + } + } +} diff --git a/lib/phpfastcache/phpFastCache/Core/DriverAbstract.php b/lib/phpfastcache/phpFastCache/Core/DriverAbstract.php new file mode 100644 index 0000000..b880401 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Core/DriverAbstract.php @@ -0,0 +1,846 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Core; + +use phpFastCache\Exceptions\phpFastCacheDriverException; +use phpFastCache\CacheManager; + +/** + * Class DriverAbstract + * @package phpFastCache\Core + */ +abstract class DriverAbstract implements DriverInterface +{ + + /** + * @var array + */ + public $extension_dir = '_extensions'; + + /** + * @var array + */ + public $tmp = array(); + + /** + * @var array default options, this will be merge to Driver's Options + */ + public $config = array(); + + /** + * @var bool + */ + public $fallback = false; + + /** + * @var + */ + public $instant; + + + public function __destruct() + { + // clean up the memory and don't want for PHP clean for caching method "phpfastcache" + if (isset($this->config[ 'instance' ]) && (int)$this->config[ 'cache_method' ] === 3) { + CacheManager::cleanCachingMethod($this->config[ 'instance' ]); + } + } + + /** + * @param $keyword + * @return string + */ + protected function encodeFilename($keyword) + { + // return trim(trim(preg_replace('/[^a-zA-Z0-9]+/', '_', $keyword), '_')); + // return rtrim(base64_encode($keyword), '='); + return md5($keyword); + } + + /** + * Basic Functions + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return bool|null + */ + public function set($keyword, $value = '', $time = 0, $option = array()) + { + /** + * Infinity Time + * Khoa. B + */ + if ((int)$time <= 0) { + /** + * 5 years, however memcached or memory cached will gone when u restart it + * just recommended for sqlite. files + */ + $time = 3600 * 24 * 365 * 5; + } + + /** + * Temporary disabled phpFastCache::$disabled = true + * Khoa. B + */ + if (phpFastCache::$disabled === true) { + return false; + } + $object = array( + "value" => $value, + "write_time" => time(), + "expired_in" => $time, + "expired_time" => time() + (int)$time, + "size" => (is_array($value) || is_object($value)) ? strlen(serialize($value)) : strlen((String)$value), + ); + + // handle search + if (isset($this->config[ 'allow_search' ]) && $this->config[ 'allow_search' ] == true) { + $option[ 'tags' ][] = "search"; + } + + // handle tags + if (isset($option[ 'tags' ])) { + $this->_handleTags($keyword, $time, $option[ 'tags' ]); + } + + // handle method + if ((int)$this->config[ 'cache_method' ] > 1 && isset($object[ 'size' ]) && (int)$object[ 'size' ] <= (int)$this->config[ 'limited_memory_each_object' ]) { + CacheManager::$memory[ $this->config[ 'instance' ] ][ $keyword ] = $object; + if (in_array((int)$this->config[ 'cache_method' ], array(3, 4))) { + return true; + } + } + $this->_hit("set", 1); + return $this->driver_set($keyword, $object, $time, $option); + + } + + /** + * @param $keyword + * @param array $option + * @return mixed + */ + public function get($keyword, $option = array()) + { + /** + * Temporary disabled phpFastCache::$disabled = true + * Khoa. B + */ + + if (phpFastCache::$disabled === true) { + return null; + } + + // handle method + if ((int)$this->config[ 'cache_method' ] > 1) { + if (isset(CacheManager::$memory[ $this->config[ 'instance' ] ][ $keyword ])) { + $object = CacheManager::$memory[ $this->config[ 'instance' ] ][ $keyword ]; + } + } + + if (!isset($object)) { + $this->_hit("get", 1); + $object = $this->driver_get($keyword, $option); + + // handle method + if ((int)$this->config[ 'cache_method' ] > 1 && isset($object[ 'size' ]) && (int)$object[ 'size' ] <= (int)$this->config[ 'limited_memory_each_object' ]) { + CacheManager::$memory[ $this->config[ 'instance' ] ][ $keyword ] = $object; + } + // end handle method + } + + if ($object == null) { + return null; + } + + $value = isset($object[ 'value' ]) ? $object[ 'value' ] : null; + return isset($option[ 'all_keys' ]) && $option[ 'all_keys' ] ? $object : $value; + } + + /** + * @param $keyword + * @param array $option + * @return null|object + */ + public function getInfo($keyword, $option = array()) + { + if ((int)$this->config[ 'cache_method' ] > 1) { + if (isset(CacheManager::$memory[ $this->config[ 'instance' ] ][ $keyword ])) { + $object = CacheManager::$memory[ $this->config[ 'instance' ] ][ $keyword ]; + } + } + if (!isset($object)) { + $object = $this->driver_get($keyword, $option); + } + if ($object == null) { + return null; + } + return $object; + } + + /** + * @param $keyword + * @param array $option + * @return mixed + */ + public function delete($keyword, array $option = array()) + { + // handle method + if ((int)$this->config[ 'cache_method' ] > 1) { + // use memory + unset(CacheManager::$memory[ $this->config[ 'instance' ] ][ $keyword ]); + } + // end handle method + return $this->driver_delete($keyword, $option); + } + + /** + * @param array $option + * @return mixed + */ + public function stats(array $option = array()) + { + return $this->driver_stats($option); + } + + /** + * @param array $option + * @return mixed + */ + public function clean(array $option = array()) + { + // handle method + if ((int)$this->config[ 'cache_method' ] > 1) { + // use memory + CacheManager::$memory[ $this->config[ 'instance' ] ] = array(); + } + // end handle method + return $this->driver_clean($option); + } + + /** + * @param $keyword + * @return bool + */ + public function isExisting($keyword) + { + if (method_exists($this, 'driver_isExisting')) { + return $this->driver_isExisting($keyword); + } + + $data = $this->get($keyword); + if ($data == null) { + return false; + } else { + return true; + } + + } + + /** + * Searches though the cache for keys that match the given query. + * @param $query_as_regex_or_string + * @param bool $search_in_value + * @return mixed + * @throws phpFastCacheDriverException + */ + public function search($query_as_regex_or_string, $search_in_value = false) + { + if ($this->config[ 'allow_search' ] != true) { + throw new phpFastCacheDriverException('Please setup allow_search = true'); + } else { + $list = $this->getTags("search", $search_in_value); + $tmp = explode("/", $query_as_regex_or_string, 2); + $regex = isset($tmp[ 1 ]) ? true : false; + $return_list = array(); + foreach ($list as $tag) { + foreach ($tag as $keyword => $value) { + $gotcha = false; + if ($search_in_value == true) { + $value = $this->get($keyword); + } + + if ($regex == true && $gotcha == false) { // look in keyword + if (preg_match($query_as_regex_or_string, $keyword)) { + $return_list[ $keyword ] = $value; + $gotcha = true; + } + } + if ($gotcha == false) { + if (strpos($keyword, $query_as_regex_or_string) !== false) { + $return_list[ $keyword ] = $value; + $gotcha = true; + } + } + + if ($search_in_value == true && $gotcha == false) { // value search + if ($regex == true && $gotcha == false) { + if (preg_match($query_as_regex_or_string, $value)) { + $return_list[ $keyword ] = $value; + $gotcha = true; + } + } + if ($gotcha == false) { + if (strpos($value, $query_as_regex_or_string) !== false) { + $return_list[ $keyword ] = $value; + $gotcha = true; + } + } + } + } // each tags loop + } // end foreach + return $return_list; + } + } + + /** + * @param $keyword + * @param int $step + * @param array $option + * @return bool + */ + public function increment($keyword, $step = 1, array $option = array()) + { + $object = $this->get($keyword, array('all_keys' => true)); + if ($object == null) { + return false; + } else { + $value = (int)$object[ 'value' ] + (int)$step; + $time = $object[ 'expired_time' ] - time(); + $this->set($keyword, $value, $time, $option); + return true; + } + } + + /** + * @param $keyword + * @param int $step + * @param array $option + * @return bool + */ + public function decrement($keyword, $step = 1, array $option = array()) + { + $object = $this->get($keyword, array('all_keys' => true)); + if ($object == null) { + return false; + } else { + $value = (int)$object[ 'value' ] - (int)$step; + $time = $object[ 'expired_time' ] - time(); + $this->set($keyword, $value, $time, $option); + return true; + } + } + + /** + * Extend more time + * @param $keyword + * @param int $time + * @param array $option + * @return bool + */ + public function touch($keyword, $time = 300, array $option = array()) + { + $object = $this->get($keyword, array('all_keys' => true)); + if ($object == null) { + return false; + } else { + $value = $object[ 'value' ]; + $time = $object[ 'expired_time' ] - time() + $time; + $this->set($keyword, $value, $time, $option); + return true; + } + } + + + /** + * Other Functions Built-int for phpFastCache since 1.3 + */ + + /** + * @param array $list + */ + public function setMulti(array $list = array()) + { + foreach ($list as $array) { + $this->set($array[ 0 ], isset($array[ 1 ]) ? $array[ 1 ] : 0, + isset($array[ 2 ]) ? $array[ 2 ] : array()); + } + } + + /** + * @param array $list + * @return array + */ + public function getMulti(array $list = array()) + { + $res = array(); + foreach ($list as $array) { + $name = $array[ 0 ]; + $res[ $name ] = $this->get($name, + isset($array[ 1 ]) ? $array[ 1 ] : array()); + } + return $res; + } + + /** + * @param array $list + * @return array + */ + public function getInfoMulti(array $list = array()) + { + $res = array(); + foreach ($list as $array) { + $name = $array[ 0 ]; + $res[ $name ] = $this->getInfo($name, + isset($array[ 1 ]) ? $array[ 1 ] : array()); + } + return $res; + } + + /** + * @param array $list + * @param array $option + */ + public function deleteMulti(array $list = array(), array $option = array()) + { + foreach ($list as $item) { + if (is_array($item) && count($item) === 2) { + $this->delete($item[ 0 ], $item[ 1 ]); + } + } + } + + /** + * @param array $list + * @return array + */ + public function isExistingMulti(array $list = array()) + { + $res = array(); + foreach ($list as $array) { + $name = $array[ 0 ]; + $res[ $name ] = $this->isExisting($name); + } + return $res; + } + + /** + * @param array $list + * @return array + */ + public function incrementMulti(array $list = array()) + { + $res = array(); + foreach ($list as $array) { + $name = $array[ 0 ]; + $res[ $name ] = $this->increment($name, $array[ 1 ], + isset($array[ 2 ]) ? $array[ 2 ] : array()); + } + return $res; + } + + /** + * @param array $list + * @return array + */ + public function decrementMulti(array $list = array()) + { + $res = array(); + foreach ($list as $array) { + $name = $array[ 0 ]; + $res[ $name ] = $this->decrement($name, $array[ 1 ], + isset($array[ 2 ]) ? $array[ 2 ] : array()); + } + return $res; + } + + /** + * @param array $list + * @return array + */ + public function touchMulti(array $list = array()) + { + $res = array(); + foreach ($list as $array) { + $name = $array[ 0 ]; + $res[ $name ] = $this->touch($name, $array[ 1 ], + isset($array[ 2 ]) ? $array[ 2 ] : array()); + } + return $res; + } + + /** + * @param $config_name + * @param string $value + */ + public function setup($config_name, $value = '') + { + /* + * Config for class + */ + if (is_array($config_name)) { + $this->config = array_merge($this->config, $config_name); + } else { + $this->config[ $config_name ] = $value; + } + } + + /** + * @param int $time + */ + public function autoCleanExpired($time = 3600) + { + } + + /** + * Magic methods + */ + + /** + * @param $name + * @return mixed + */ + public function __get($name) + { + return $this->get($name); + } + + /** + * @param $name + * @param $v + * @return bool|null + * @throws \Exception + */ + public function __set($name, $v) + { + if (isset($v[ 1 ]) && is_scalar($v[ 1 ])) { + return $this->set($name, $v[ 0 ], $v[ 1 ], + isset($v[ 2 ]) ? $v[ 2 ] : array()); + } else { + throw new phpFastCacheDriverException("Example ->$name = array('VALUE', 300);", 98); + } + } + + + /** + * Base Methods + */ + + + /** + * @return mixed + */ + protected function backup() + { + return phpFastCache(phpFastCache::$config[ 'fallback' ]); + } + + /** + * @param $name + * @return void + */ + protected function required_extension($name) + { + require_once(__DIR__ . '/../' . $this->extension_dir . '/' . $name . '.' . PHP_EXT); + } + + + /** + * @param $file + * @return string + * @throws \Exception + */ + protected function readfile($file) + { + if (function_exists('file_get_contents')) { + return file_get_contents($file); + } else { + $string = ''; + + $file_handle = @fopen($file, 'r'); + if (!$file_handle) { + throw new phpFastCacheDriverException("Can't Read File", 96); + + } + while (!feof($file_handle)) { + $line = fgets($file_handle); + $string .= $line; + } + fclose($file_handle); + + return $string; + } + } + + /** + * return PATH for Files & PDO only + * @param bool $create_path + * @return string + * @throws \Exception + */ + public function getPath($create_path = false) + { + return phpFastCache::getPath($create_path, $this->config); + } + + + /** + * Object for Files & SQLite + * @param $data + * @return string + */ + protected function encode($data) + { + return serialize($data); + } + + /** + * @param $value + * @return mixed + */ + protected function decode($value) + { + $x = @unserialize($value); + if ($x == false) { + return $value; + } else { + return $x; + } + } + + /** + * Check phpModules or CGI + * @return bool + */ + protected function isPHPModule() + { + return phpFastCache::isPHPModule(); + } + + + /** + * @param $class + * @return bool + */ + protected function isExistingDriver($class) + { + return class_exists("\\phpFastCache\\Drivers\\{$class}"); + } + + + /** + * @return int + */ + protected function __setChmodAuto() + { + return phpFastCache::__setChmodAuto($this->config); + } + + + /** + * @param $tag + * @return string + */ + protected function _getTagName($tag) + { + return "__tag__" . $tag; + } + + /** + * @return \phpFastCache\Core\DriverAbstract + */ + protected function _tagCaching() + { + return CacheManager::Sqlite( + array( + "path" => $this->config[ 'path' ], + "cache_method" => 3, + ) + ); + } + + /** + * @param string $keyword + * @param mixed $value + * @param integer $time + * @param array $tags + * @param array $option | $option = array("tags" => array("a","b","c") + * @return mixed + */ + public function setTags($keyword, $value = '', $time = 0, $tags = array(), $option = array()) + { + if (!is_array($tags)) { + $tags = array($tags); + } + $option[ 'tags' ] = $tags; + return $this->set($keyword, $value, $time, $option); + } + + protected function _handleTags($keyword, $time, $tags) + { + foreach ($tags as $tag) { + $list = $this->_tagCaching()->get($this->_getTagName($tag)); + if (is_null($list)) { + $list = array(); + } + $list[ $keyword ] = time() + $time; + $this->_tagCaching()->set($this->_getTagName($tag), $list, 3600 * 24 * 30); + } + } + + + /** + * @param array $tags + * @param bool $return_content + * @param array $option | $option = array("tags" => array("a","b","c") + * @return array + */ + public function getTags($tags = array(), $return_content = true, $option = array()) + { + if (!is_array($tags)) { + $tags = array($tags); + } + $keywords = array(); + $tmp = 0; + + foreach ($tags as $tag) { + $list = $this->_tagCaching()->get($this->_getTagName($tag)); + $list_return = array(); + if (is_null($list)) { + $list = array(); + } + foreach ($list as $keyword => $time) { + if ($time <= time()) { + unset($list[ $keyword ]); + } else { + if ($tmp < $time) { + $tmp = $time; + } + if ($return_content == true) { + $list_return[ $keyword ] = $this->get($keyword); + } else { + $list_return[ $keyword ] = $time; + } + } + } + + $this->_tagCaching()->set($this->_getTagName($tag), $list, $tmp); + $keywords[ $tag ] = $list_return; + } + return $keywords; + } + + /** + * @param array $tags | array("a","b","c") + * @param int $time + * @param array $options + * @return mixed + * @internal param array $option | $option = array("tags" => array("a","b","c") + */ + public function touchTags($tags = array(), $time = 300, $options = array()) + { + if (!is_array($tags)) { + $tags = array($tags); + } + $lists = $this->getTags($tags); + foreach ($lists as $tag => $keywords) { + foreach ($keywords as $keyword => $time) { + $this->touch($keyword, $time, $options); + } + } + return true; + } + + /** + * @param array $tags | array("a","b","c") + * @param array $option | $option = array("tags" => array("a","b","c") + * @return mixed + */ + public function deleteTags($tags = array(), $option = array()) + { + if (!is_array($tags)) { + $tags = array($tags); + } + $lists = $this->getTags($tags); + foreach ($lists as $tag => $keywords) { + foreach ($keywords as $keyword => $time) { + $this->delete($keyword, $option); + } + } + return true; + } + + + /** + * @param array $tags | array("a","b","c") + * @param integer + * @param array $option | $option = array("tags" => array("a","b","c") + * @return mixed + */ + public function incrementTags($tags = array(), $step = 1, $option = array()) + { + if (!is_array($tags)) { + $tags = array($tags); + } + $lists = $this->getTags($tags); + foreach ($lists as $tag => $keywords) { + foreach ($keywords as $keyword => $time) { + $this->increment($keyword, $step, $option); + } + } + return true; + } + + /** + * @param array $tags | array("a","b","c") + * @param integer + * @param array $option | $option = array("tags" => array("a","b","c") + * @return mixed + */ + public function decrementTags($tags = array(), $step = 1, $option = array()) + { + if (!is_array($tags)) { + $tags = array($tags); + } + $lists = $this->getTags($tags); + foreach ($lists as $tag => $keywords) { + foreach ($keywords as $keyword => $time) { + $this->decrement($keyword, $step, $option); + } + } + return true; + } + + /** + * @param $value + */ + protected function _kbdebug($value) + { + /* + echo "
";
+        print_r($value);
+        echo "
"; + */ + } + + public function _hit($index, $step = 1) + { + $instance = $this->config[ 'instance' ]; + $current = isset(CacheManager::$hit[ $instance ][ 'data' ][ $index ]) ? CacheManager::$hit[ $instance ][ 'data' ][ $index ] : 0; + CacheManager::$hit[ $instance ][ 'data' ][ $index ] = $current + ($step); + } + +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Core/DriverInterface.php b/lib/phpfastcache/phpFastCache/Core/DriverInterface.php new file mode 100644 index 0000000..1724374 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Core/DriverInterface.php @@ -0,0 +1,86 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Core; + +/** + * Interface DriverInterface + * @package phpFastCache\Core + */ +interface DriverInterface +{ + /** + * Check if this Cache driver is available for server or not + * phpFastCache_driver constructor. + * @param array $config + */ + public function __construct($config = array()); + + /** + * @return mixed + */ + public function checkdriver(); + + /** + * Set a obj to cache + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return mixed + */ + public function driver_set( + $keyword, + $value = '', + $time = 300, + $option = array() + ); + + /** + * Return null or value of cache + * @param $keyword + * @param array $option + * @return mixed + */ + public function driver_get($keyword, $option = array()); + + /** + * Show stats of caching + * Return array("info","size","data") + * @param array $option + * @return mixed + */ + public function driver_stats($option = array()); + + /** + * Delete a cache + * @param $keyword + * @param array $option + * @return mixed + */ + public function driver_delete($keyword, $option = array()); + + /** + * Clean up whole cache + * @param array $option + * @return mixed + */ + public function driver_clean($option = array()); + + /** + * @param $config_name + * @param string $value + */ + public function setup($config_name, $value = ''); +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Core/phpFastCache.php b/lib/phpfastcache/phpFastCache/Core/phpFastCache.php new file mode 100644 index 0000000..e584e85 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Core/phpFastCache.php @@ -0,0 +1,354 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Core; + +use phpFastCache\CacheManager; +use phpFastCache\Exceptions\phpFastCacheCoreException; +use phpFastCache\Exceptions\phpFastCacheDriverException; + +/** + * Class phpFastCache + * @package phpFastCache\Core + * + * Handle methods using annotations for IDE + * because they're handled by __call() + * Check out DriverInterface to see all + * the drivers methods magically implemented + * + * @method get() driver_get($keyword, $option = array()) Return null or value of cache + * @method set() driver_set($keyword, $value = '', $time = 300, $option = array()) Set a obj to cache + * @method delete() delete(string $keyword) Delete key from cache + * @method clean() clean($option = array()) Clean up whole cache + * @method checkdriver() checkdriver() Delete key from cache + * @method stats() stats($option = array()) Show stats of caching + * @method systemInfo() systemInfo() Return System Information + * + */ +class phpFastCache +{ + /** + * @var bool + */ + public static $disabled = false; + + /** + * @var array + */ + public static $config = array( + 'storage' => '', // blank for auto + 'default_chmod' => 0777, // 0777 , 0666, 0644 + + 'overwrite' => "", // files, sqlite, etc it will overwrite ur storage and all other caching for waiting u fix ur server + 'allow_search' => false, // turn to true will allow $method search("/regex/") + + 'fallback' => 'files', //Fall back when old driver is not support + + 'securityKey' => 'auto', + 'htaccess' => true, + 'path' => '', + + 'memcache' => array( + array('127.0.0.1', 11211, 1), + // array("new.host.ip",11211,1), + ), + + 'redis' => array( + 'host' => '127.0.0.1', + 'port' => '', + 'password' => '', + 'database' => '', + 'timeout' => '', + ), + + 'ssdb' => array( + 'host' => '127.0.0.1', + 'port' => 8888, + 'password' => '', + 'timeout' => '', + ), + + 'extensions' => array(), + "cache_method" => 1, // 1 = normal, 2 = phpfastcache, 3 = memory + "limited_memory_each_object" => 4000, // maximum size (bytes) of object store in memory + "compress_data" => false // compress stored data, if the backend supports it + ); + + /** + * @var array + */ + protected static $tmp = array(); + + /** + * @var DriverAbstract $instance + */ + public $instance; + + /** + * phpFastCache constructor. + * @param string $storage + * @param array $config + */ + public function __construct($storage = '', $config = array()) + { + if (empty($config)) { + $config = phpFastCache::$config; + } + $config[ 'storage' ] = $storage; + + $storage = strtolower($storage); + if ($storage == '' || $storage == 'auto') { + $storage = self::getAutoClass($config); + } + + $this->instance = CacheManager::getInstance($storage, $config); + } + + /** + * Cores + */ + + /** + * @param $config + * @return string + * @throws \Exception + */ + public static function getAutoClass($config) + { + $path = self::getPath(false, $config); + if (is_writable($path)) { + $driver = 'files'; + } else if (extension_loaded('apc') && ini_get('apc.enabled') && strpos(PHP_SAPI, 'CGI') === false) { + $driver = 'apc'; + } else if (class_exists('memcached')) { + $driver = 'memcached'; + } elseif (extension_loaded('wincache') && function_exists('wincache_ucache_set')) { + $driver = 'wincache'; + } elseif (extension_loaded('xcache') && function_exists('xcache_get')) { + $driver = 'xcache'; + } else if (function_exists('memcache_connect')) { + $driver = 'memcache'; + } else if (class_exists('Redis')) { + $driver = 'redis'; + } else { + $driver = 'files'; + } + + return $driver; + } + + /** + * @param bool $skip_create_path + * @param $config + * @return string + * @throws \Exception + */ + public static function getPath($skip_create_path = false, $config) + { + $tmp_dir = ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir(); + + if (!isset($config[ 'path' ]) || $config[ 'path' ] == '') { + if (self::isPHPModule()) { + $path = $tmp_dir; + } else { + $document_root_path = rtrim($_SERVER[ 'DOCUMENT_ROOT' ], '/') . '/../'; + $path = isset($_SERVER[ 'DOCUMENT_ROOT' ]) && is_writable($document_root_path) + ? $document_root_path + : rtrim(__DIR__, '/') . '/'; + } + + if (self::$config[ 'path' ] != '') { + $path = $config[ 'path' ]; + } + + } else { + $path = $config[ 'path' ]; + } + + $securityKey = array_key_exists('securityKey', + $config) ? $config[ 'securityKey' ] : ''; + if ($securityKey == "" || $securityKey == 'auto') { + $securityKey = self::$config[ 'securityKey' ]; + if ($securityKey == 'auto' || $securityKey == '') { + $securityKey = isset($_SERVER[ 'HTTP_HOST' ]) ? preg_replace('/^www./', + '', strtolower(str_replace(':', '_', $_SERVER[ 'HTTP_HOST' ]))) : "default"; + } + } + if ($securityKey != '') { + $securityKey .= '/'; + } + + $securityKey = self::cleanFileName($securityKey); + + $full_path = rtrim($path,'/') . '/' . $securityKey; + $full_pathx = md5($full_path); + + + if ($skip_create_path == false && !isset(self::$tmp[ $full_pathx ])) { + + if (!@file_exists($full_path) || !@is_writable($full_path)) { + if (!@file_exists($full_path)) { + @mkdir($full_path, self::__setChmodAuto($config), true); + } + if (!@is_writable($full_path)) { + @chmod($full_path, self::__setChmodAuto($config)); + } + if(!@is_writable($full_path)) { + // switch back to tmp dir again if the path is not writeable + $full_path = rtrim($tmp_dir,'/') . '/' . $securityKey; + if (!@file_exists($full_path)) { + @mkdir($full_path, self::__setChmodAuto($config), true); + } + if (!@is_writable($full_path)) { + @chmod($full_path, self::__setChmodAuto($config)); + } + } + if (!@file_exists($full_path) || !@is_writable($full_path)) { + throw new phpFastCacheCoreException('PLEASE CREATE OR CHMOD ' . $full_path . ' - 0777 OR ANY WRITABLE PERMISSION!', 92); + } + } + + self::$tmp[ $full_pathx ] = true; + self::htaccessGen($full_path, array_key_exists('htaccess', $config) ? $config[ 'htaccess' ] : false); + } + + return realpath($full_path); + + } + + /** + * @param $filename + * @return mixed + */ + public static function cleanFileName($filename) + { + $regex = array( + '/[\?\[\]\/\\\=\<\>\:\;\,\'\"\&\$\#\*\(\)\|\~\`\!\{\}]/', + '/\.$/', + '/^\./', + ); + $replace = array('-', '', ''); + return trim(preg_replace($regex, $replace, trim($filename)),'-'); + } + + /** + * @param $config + * @return int + */ + public static function __setChmodAuto($config) + { + if (!isset($config[ 'default_chmod' ]) || $config[ 'default_chmod' ] == '' || is_null($config[ 'default_chmod' ])) { + return 0777; + } else { + return $config[ 'default_chmod' ]; + } + } + + /** + * @return array + */ + protected static function getOS() + { + $os = array( + 'os' => PHP_OS, + 'php' => PHP_SAPI, + 'system' => php_uname(), + 'unique' => md5(php_uname() . PHP_OS . PHP_SAPI), + ); + return $os; + } + + /** + * @return bool + */ + public static function isPHPModule() + { + if (PHP_SAPI === 'apache2handler') { + return true; + } else { + if (strpos(PHP_SAPI, 'handler') !== false) { + return true; + } + } + return false; + } + + /** + * @param $path + * @param bool $create + * @throws \Exception + */ + protected static function htaccessGen($path, $create = true) + { + + if ($create == true) { + if (!is_writable($path)) { + try { + chmod($path, 0777); + } catch (phpFastCacheDriverException $e) { + throw new phpFastCacheDriverException('PLEASE CHMOD ' . $path . ' - 0777 OR ANY WRITABLE PERMISSION!', + 92); + } + } + + if(!file_exists($path."/.htaccess")) { + // echo "write me"; + $html = "order deny, allow \r\n +deny from all \r\n +allow from 127.0.0.1"; + + $f = @fopen($path . '/.htaccess', 'w+'); + if (!$f) { + throw new phpFastCacheDriverException('PLEASE CHMOD ' . $path . ' - 0777 OR ANY WRITABLE PERMISSION!', 92); + } + fwrite($f, $html); + fclose($f); + + + } + } + + } + + /** + * @param $name + * @param string $value + */ + public static function setup($name, $value = '') + { + if (is_array($name)) { + self::$config = array_merge(self::$config,$name); + } else { + self::$config[ $name ] = $value; + } + } + + /** + * @param $something + */ + public static function debug($something) + { + echo "Starting Debugging ...
\r\n "; + if (is_array($something)) { + echo '
';
+            print_r($something);
+            echo '
'; + var_dump($something); + } else { + echo $something; + } + echo "\r\n
Ended"; + exit; + } +} diff --git a/lib/phpfastcache/phpFastCache/Core/phpFastCacheExtensions.php b/lib/phpfastcache/phpFastCache/Core/phpFastCacheExtensions.php new file mode 100644 index 0000000..813980f --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Core/phpFastCacheExtensions.php @@ -0,0 +1,31 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Core; + +/** + * Class phpFastCacheExtensions + * @package phpFastCache\Core + */ +abstract class phpFastCacheExtensions +{ + /** + * @param $name + * @param $agr + */ + public function __call($name, $agr) + { + + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/apc.php b/lib/phpfastcache/phpFastCache/Drivers/apc.php new file mode 100644 index 0000000..36618fe --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/apc.php @@ -0,0 +1,137 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use phpFastCache\Exceptions\phpFastCacheDriverException; + +/** + * Class apc + * @package phpFastCache\Drivers + */ +class apc extends DriverAbstract +{ + /** + * phpFastCache_apc constructor. + * @param array $config + * @throws phpFastCacheDriverException + */ + public function __construct($config = array()) + { + $this->setup($config); + + if (!$this->checkdriver()) { + throw new phpFastCacheDriverException('APC is not installed, cannot continue.'); + } + } + + /** + * @return bool + */ + public function checkdriver() + { + if (extension_loaded('apc') && ini_get('apc.enabled')) { + return true; + } else { + $this->fallback = true; + return false; + } + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return array|bool + */ + public function driver_set( + $keyword, + $value = '', + $time = 300, + $option = array() + ) { + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true) { + return apc_add($keyword, $value, $time); + } else { + return apc_store($keyword, $value, $time); + } + } + + /** + * @param $keyword + * @param array $option + * @return mixed|null + */ + public function driver_get($keyword, $option = array()) + { + $data = apc_fetch($keyword, $bo); + if ($bo === false) { + return null; + } + return $data; + + } + + /** + * @param $keyword + * @param array $option + * @return bool|\string[] + */ + public function driver_delete($keyword, $option = array()) + { + return apc_delete($keyword); + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + $res = array( + 'info' => '', + 'size' => '', + 'data' => '', + ); + + try { + $res[ 'data' ] = apc_cache_info('user'); + } catch (\Exception $e) { + $res[ 'data' ] = array(); + } + + return $res; + } + + /** + * @param array $option + * @return void + */ + public function driver_clean($option = array()) + { + @apc_clear_cache(); + @apc_clear_cache('user'); + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + return (bool) apc_exists($keyword); + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/cookie.php b/lib/phpfastcache/phpFastCache/Drivers/cookie.php new file mode 100644 index 0000000..1326241 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/cookie.php @@ -0,0 +1,156 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; + +/** + * Class cookie + * @package phpFastCache\Drivers + */ +class cookie extends DriverAbstract +{ + /** + * phpFastCache_cookie constructor. + * @param array $config + */ + public function __construct($config = array()) + { + $this->setup($config); + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + $this->fallback = true; + } + } + + /** + * @return bool + */ + public function checkdriver() + { + // Check memcache + if (function_exists('setcookie')) { + return true; + } + $this->fallback = true; + return false; + } + + /** + * + */ + public function connectServer() + { + // for cookie check output + if (!isset($_COOKIE[ 'phpFastCache' ])) { + if (!@setcookie('phpFastCache', 1, 10)) { + $this->fallback = true; + } + } + + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return bool + */ + public function driver_set($keyword, $value = '', $time = 300, $option = array()) + { + $this->connectServer(); + $keyword = 'phpFastCache_' . $keyword; + $v = $this->encode($value); + if(isset($this->config['limited_memory_each_object']) + && strlen($v) > $this->config['limited_memory_each_object']) { + return false; + } + return setcookie($keyword, $v, time() + ($time ? (int)$time : 300), '/'); + + } + + /** + * @param $keyword + * @param array $option + * @return bool|mixed|null + */ + public function driver_get($keyword, $option = array()) + { + $this->connectServer(); + // return null if no caching + // return value if in caching + $keyword = 'phpFastCache_' . $keyword; + $x = isset($_COOKIE[ $keyword ]) ? $this->decode($_COOKIE[ $keyword ]) : false; + if ($x == false) { + return null; + } else { + return $x; + } + } + + /** + * @param $keyword + * @param array $option + */ + public function driver_delete($keyword, $option = array()) + { + $this->connectServer(); + $keyword = 'phpFastCache_' . $keyword; + @setcookie($keyword, null, -10); + $_COOKIE[ $keyword ] = null; + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + $this->connectServer(); + $res = array( + 'info' => '', + 'size' => '', + 'data' => $_COOKIE, + ); + + return $res; + } + + /** + * @param array $option + */ + public function driver_clean($option = array()) + { + $this->connectServer(); + foreach ($_COOKIE as $keyword => $value) { + if (strpos($keyword, 'phpFastCache') !== false) { + @setcookie($keyword, null, -10); + $_COOKIE[ $keyword ] = null; + } + } + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + $this->connectServer(); + $x = $this->get($keyword); + + return !($x == null); + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/example.php b/lib/phpfastcache/phpFastCache/Drivers/example.php new file mode 100644 index 0000000..7d34b57 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/example.php @@ -0,0 +1,128 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use phpFastCache\Core\DriverInterface; +use phpFastCache\Exceptions\phpFastCacheDriverException; + +/** + * Class example + * @package phpFastCache\Drivers + */ +class example extends DriverAbstract +{ + /** + * phpFastCache_example constructor. + * @param array $config + * @throws phpFastCacheDriverException + */ + public function __construct($config = array()) + { + $this->setup($config); + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + throw new phpFastCacheDriverException("Can't use this driver for your website!"); + } + + } + + /** + * @return bool + */ + public function checkdriver() + { + return false; + } + + /** + * + */ + public function connectServer() + { + + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return void + */ + public function driver_set($keyword, $value = '', $time = 300, $option = array()) + { + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true) { + // skip driver + } else { + // add driver + } + + } + + /** + * @param $keyword + * @param array $option + * @return null + */ + public function driver_get($keyword, $option = array()) + { + // return null if no caching + // return value if in caching + + return null; + } + + /** + * @param $keyword + * @param array $option + * @return void + */ + public function driver_delete($keyword, $option = array()) + { + + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + $res = array( + 'info' => '', + 'size' => '', + 'data' => '', + ); + + return $res; + } + + /** + * @param array $option + * @return void + */ + public function driver_clean($option = array()) + { + + } + + /** + * @param $keyword + */ + public function driver_isExisting($keyword) + { + + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/files.php b/lib/phpfastcache/phpFastCache/Drivers/files.php new file mode 100644 index 0000000..c8a46c1 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/files.php @@ -0,0 +1,306 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use phpFastCache\Exceptions\phpFastCacheDriverException; + +/** + * Class files + * @package phpFastCache\Drivers + */ +class files extends DriverAbstract +{ + /** + * Init Cache Path + * phpFastCache_files constructor. + * @param array $config + * @throws phpFastCacheDriverException + */ + public function __construct($config = array()) + { + $this->setup($config); + $this->getPath(); // force create path + + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + throw new phpFastCacheDriverException("Can't use this driver for your website!"); + } + } + + /** + * @return bool + */ + public function checkdriver() + { + if (is_writable($this->getPath())) { + return true; + }/* else { + + }*/ + return false; + } + + /** + * @param $keyword + * @param bool $skip + * @return string + * @throws phpFastCacheDriverException + */ + private function getFilePath($keyword, $skip = false) + { + $path = $this->getPath(); + + $filename = $this->encodeFilename($keyword); + $folder = substr($filename, 0, 2); + $path = rtrim($path, '/') . '/' . $folder; + /** + * Skip Create Sub Folders; + */ + if ($skip == false) { + if (!file_exists($path)) { + if (!mkdir($path, $this->__setChmodAuto(), true)) { + throw new phpFastCacheDriverException('PLEASE CHMOD ' . $this->getPath() . ' - 0777 OR ANY WRITABLE PERMISSION!', 92); + } + } + } + + return $path . '/' . $filename . '.txt'; + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return bool + * @throws \Exception + */ + public function driver_set($keyword, $value = '', $time = 300, $option = array()) + { + $file_path = $this->getFilePath($keyword); + $data = $this->encode($value); + + $toWrite = true; + /* + * Skip if Existing Caching in Options + */ + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true && file_exists($file_path)) { + $content = $this->readfile($file_path); + $old = $this->decode($content); + $toWrite = false; + if ($this->isExpired($old)) { + $toWrite = true; + } + } + + // Force write + try { + if ($toWrite == true) { + $f = fopen($file_path, 'w+'); + fwrite($f, $data); + fclose($f); + return true; + } + } catch (\Exception $e) { + return false; + } + + return false; + } + + /** + * @param $keyword + * @param array $option + * @return mixed|null + * @throws \Exception + */ + public function driver_get($keyword, $option = array()) + { + + $file_path = $this->getFilePath($keyword); + if (!file_exists($file_path)) { + return null; + } + + $content = $this->readfile($file_path); + $object = $this->decode($content); + if ($this->isExpired($object)) { + @unlink($file_path); + $this->autoCleanExpired(); + return null; + } + + return $object; + } + + /** + * @param $keyword + * @param array $option + * @return bool + * @throws \Exception + */ + public function driver_delete($keyword, $option = array()) + { + $file_path = $this->getFilePath($keyword, true); + if (file_exists($file_path) && @unlink($file_path)) { + return true; + } else { + return false; + } + } + + /** + * Return total cache size + auto removed expired files + * @param array $option + * @return array + * @throws \Exception + */ + public function driver_stats($option = array()) + { + $res = array( + 'info' => '', + 'size' => '', + 'data' => '', + ); + + $path = $this->getPath(); + $dir = @opendir($path); + if (!$dir) { + throw new phpFastCacheDriverException("Can't read PATH:" . $path, 94); + } + + $total = 0; + $removed = 0; + while ($file = readdir($dir)) { + if ($file != '.' && $file != '..' && is_dir($path . '/' . $file)) { + // read sub dir + $subdir = opendir($path . "/" . $file); + if (!$subdir) { + throw new phpFastCacheDriverException("Can't read path:" . $path . '/' . $file, 93); + } + + while ($f = readdir($subdir)) { + if ($f != '.' && $f != '..') { + $file_path = $path . '/' . $file . '/' . $f; + $size = filesize($file_path); + $object = $this->decode($this->readfile($file_path)); + + if (strpos($f, '.') === false) { + $key = $f; + } else { + //Because PHP 5.3, this cannot be written in single line + $key = explode('.', $f); + $key = $key[ 0 ]; + } + $content[ $key ] = array( + 'size' => $size, + 'write_time' => (isset($object[ 'write_time' ]) ? $object[ 'write_time' ] : null), + ); + if ($this->isExpired($object)) { + @unlink($file_path); + $removed += $size; + } + $total += $size; + } + } + } + } + + $res[ 'size' ] = $total - $removed; + $res[ 'info' ] = array( + 'Total [bytes]' => $total, + 'Expired and removed [bytes]' => $removed, + 'Current [bytes]' => $res[ 'size' ], + ); + $res[ "data" ] = $content; + return $res; + } + + + /** + * @param int $time + */ + public function autoCleanExpired($time = 3600) + { + $autoclean = $this->get('keyword_clean_up_driver_files'); + if ($autoclean == null) { + $this->set('keyword_clean_up_driver_files', $time); + $res = $this->stats(); + } + } + + /** + * @param array $option + * @throws \Exception + * @return void + */ + public function driver_clean($option = array()) + { + + $path = $this->getPath(); + $dir = @opendir($path); + if (!$dir) { + throw new phpFastCacheDriverException("Can't read PATH:" . $path, 94); + } + + while ($file = readdir($dir)) { + if ($file != '.' && $file != '..' && is_dir($path . '/' . $file)) { + // read sub dir + $subdir = @opendir($path . '/' . $file); + if (!$subdir) { + throw new phpFastCacheDriverException("Can't read path:" . $path . '/' . $file, 93); + } + + while ($f = readdir($subdir)) { + if ($f != '.' && $f != '..') { + $file_path = $path . '/' . $file . '/' . $f; + @unlink($file_path); + } + } + } + } + } + + /** + * @param $keyword + * @return bool + * @throws \Exception + */ + public function driver_isExisting($keyword) + { + $file_path = $this->getFilePath($keyword, true); + if (!file_exists($file_path)) { + return false; + } else { + // check expired or not + $value = $this->get($keyword); + + return !($value == null); + } + } + + /** + * @param $object + * @return bool + */ + public function isExpired($object) + { + if (isset($object[ 'expired_time' ]) && time() >= $object[ 'expired_time' ]) { + return true; + } else { + return false; + } + } +} diff --git a/lib/phpfastcache/phpFastCache/Drivers/memcache.php b/lib/phpfastcache/phpFastCache/Drivers/memcache.php new file mode 100644 index 0000000..9ba830c --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/memcache.php @@ -0,0 +1,200 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use Memcache as MemcacheSoftware; + +/** + * Class memcache + * @package phpFastCache\Drivers + */ +class memcache extends DriverAbstract +{ + + /** + * @var \Memcache + */ + public $instant; + + /** + * @var int + */ + protected $memcacheFlags = 0; + + /** + * phpFastCache_memcache constructor. + * @param array $config + */ + public function __construct($config = array()) + { + $this->setup($config); + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + $this->fallback = true; + } + if (class_exists('Memcache')) { + $this->instant = new MemcacheSoftware(); + + if (array_key_exists('compress_data', $config) && $config[ 'compress_data' ] === true) { + $this->memcacheFlags = MEMCACHE_COMPRESSED; + } + } else { + $this->fallback = true; + } + } + + /** + * @return bool + */ + public function checkdriver() + { + // Check memcache + if (function_exists('memcache_connect')) { + return true; + } + $this->fallback = true; + return false; + } + + /** + * + */ + public function connectServer() + { + $server = $this->config[ 'memcache' ]; + if (count($server) < 1) { + $server = array( + array('127.0.0.1', 11211), + ); + } + + foreach ($server as $s) { + $name = $s[ 0 ] . "_" . $s[ 1 ]; + if (!isset($this->checked[ $name ])) { + try { + if (!$this->instant->addserver($s[ 0 ], $s[ 1 ])) { + $this->fallback = true; + } + + $this->checked[ $name ] = 1; + } catch (\Exception $e) { + $this->fallback = true; + } + + + } + + } + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return array|bool + */ + public function driver_set( + $keyword, + $value = '', + $time = 300, + $option = array() + ) { + $this->connectServer(); + + // Memcache will only allow a expiration timer less than 2592000 seconds, + // otherwise, it will assume you're giving it a UNIX timestamp. + if ($time > 2592000) { + $time = time() + $time; + } + + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true) { + return $this->instant->add($keyword, $value, $this->memcacheFlags, $time); + + } else { + return $this->instant->set($keyword, $value, $this->memcacheFlags, $time); + } + } + + /** + * @param $keyword + * @param array $option + * @return array|null|string + */ + public function driver_get($keyword, $option = array()) + { + $this->connectServer(); + + // return null if no caching + // return value if in caching + + $x = $this->instant->get($keyword); + + if ($x == false) { + return null; + } else { + return $x; + } + + } + + /** + * @param $keyword + * @param array $option + */ + public function driver_delete($keyword, $option = array()) + { + $this->connectServer(); + $this->instant->delete($keyword); + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + $this->connectServer(); + $res = array( + 'info' => '', + 'size' => '', + 'data' => $this->instant->getStats(), + ); + + return $res; + + } + + /** + * @param array $option + */ + public function driver_clean($option = array()) + { + $this->connectServer(); + $this->instant->flush(); + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + $this->connectServer(); + $x = $this->get($keyword); + + return !($x == null); + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/memcached.php b/lib/phpfastcache/phpFastCache/Drivers/memcached.php new file mode 100644 index 0000000..a93735f --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/memcached.php @@ -0,0 +1,200 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use Memcached as MemcachedSoftware; + +/** + * Class memcached + * @package phpFastCache\Drivers + */ +class memcached extends DriverAbstract +{ + + /** + * @var \Memcached + */ + public $instant; + + /** + * phpFastCache_memcached constructor. + * @param array $config + */ + public function __construct($config = array()) + { + $this->setup($config); + + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + $this->fallback = true; + } + + if (class_exists('Memcached')) { + $this->instant = new MemcachedSoftware(); + } else { + $this->fallback = true; + } + + } + + /** + * @return bool + */ + public function checkdriver() + { + if (class_exists('Memcached')) { + return true; + } + $this->fallback = true; + return false; + } + + + /** + * @return bool + */ + public function connectServer() + { + if ($this->checkdriver() == false) { + return false; + } + + $s = $this->config[ 'memcache' ]; + if (count($s) < 1) { + $s = array( + array('127.0.0.1', 11211, 100), + ); + } + + foreach ($s as $server) { + $name = isset($server[ 0 ]) ? $server[ 0 ] : '127.0.0.1'; + $port = isset($server[ 1 ]) ? $server[ 1 ] : 11211; + $sharing = isset($server[ 2 ]) ? $server[ 2 ] : 0; + $checked = $name . '_' . $port; + if (!isset($this->checked[ $checked ])) { + try { + if ($sharing > 0) { + if (!$this->instant->addServer($name, $port, + $sharing) + ) { + $this->fallback = true; + } + } else { + + if (!$this->instant->addServer($name, $port)) { + $this->fallback = true; + } + } + $this->checked[ $checked ] = 1; + } catch (\Exception $e) { + $this->fallback = true; + } + + } + } + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return bool + */ + public function driver_set($keyword, $value = '', $time = 300, $option = array()) + { + $this->connectServer(); + + // Memcache will only allow a expiration timer less than 2592000 seconds, + // otherwise, it will assume you're giving it a UNIX timestamp. + if ($time > 2592000) { + $time = time() + $time; + } + + if (isset($option[ 'isExisting' ]) && $option[ 'isExisting' ] == true) { + return $this->instant->add($keyword, $value, $time); + } else { + return $this->instant->set($keyword, $value, $time); + + } + } + + /** + * @param $keyword + * @param array $option + * @return mixed|null + */ + public function driver_get($keyword, $option = array()) + { + // return null if no caching + // return value if in caching + $this->connectServer(); + $x = @$this->instant->get($keyword);// Prevent memcached to return a warning for long keywords + if ($x == false) { + return null; + } else { + return $x; + } + } + + /** + * @param $keyword + * @param array $option + * @return void + */ + public function driver_delete($keyword, $option = array()) + { + $this->connectServer(); + $this->instant->delete($keyword); + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + $this->connectServer(); + $res = array( + 'info' => '', + 'size' => '', + 'data' => $this->instant->getStats(), + ); + + return $res; + } + + /** + * @param array $option + * @return void + */ + public function driver_clean($option = array()) + { + $this->connectServer(); + $this->instant->flush(); + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + $this->connectServer(); + $x = $this->get($keyword); + + return !($x == null); + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/mongodb.php b/lib/phpfastcache/phpFastCache/Drivers/mongodb.php new file mode 100644 index 0000000..2b8d230 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/mongodb.php @@ -0,0 +1,125 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use phpFastCache\Exceptions\phpFastCacheDriverException; + +/** + * Class mongodb + * @package phpFastCache\Drivers + */ +class mongodb extends DriverAbstract +{ + /** + * phpFastCache constructor. + * @param array $config + * @throws phpFastCacheDriverException + */ + public function __construct($config = array()) + { + $this->setup($config); + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + throw new phpFastCacheDriverException("Can't use this driver for your website!"); + } + + } + + /** + * @return bool + */ + public function checkdriver() + { + // return true; + return false; + } + + /** + * + */ + public function connectServer() + { + + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + */ + public function driver_set($keyword, $value = '', $time = 300, $option = array()) + { + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true) { + // skip driver + } else { + // add driver + } + + } + + /** + * @param $keyword + * @param array $option + * @return null + */ + public function driver_get($keyword, $option = array()) + { + // return null if no caching + // return value if in caching + + return null; + } + + /** + * @param $keyword + * @param array $option + */ + public function driver_delete($keyword, $option = array()) + { + + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + $res = array( + 'info' => '', + 'size' => '', + 'data' => '', + ); + + return $res; + } + + /** + * @param array $option + */ + public function driver_clean($option = array()) + { + + } + + /** + * @param $keyword + */ + public function driver_isExisting($keyword) + { + + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/predis.php b/lib/phpfastcache/phpFastCache/Drivers/predis.php new file mode 100644 index 0000000..c0654e8 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/predis.php @@ -0,0 +1,222 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use Predis\Client as PredisSoftware; + +/** + * Class predis + * @package phpFastCache\Drivers + */ +class predis extends DriverAbstract +{ + + /** + * @var bool + */ + public $checked_redis = false; + + /** + * phpFastCache_predis constructor. + * @param array $config + */ + public function __construct($config = array()) + { + $this->setup($config); + if (!class_exists("\\Predis\\Client")) { + $this->required_extension("predis-1.0/autoload"); + } + } + + /** + * @return bool + */ + public function checkdriver() + { + // Check memcache + if (!class_exists("\\Predis\\Client")) { + $this->required_extension("predis-1.0/autoload"); + try { + \Predis\Autoloader::register(); + } catch (\Exception $e) { + + } + } + return true; + } + + + /** + * @return bool + */ + public function connectServer() + { + + $server = isset($this->config[ 'redis' ]) ? $this->config[ 'redis' ] : array( + 'host' => '127.0.0.1', + 'port' => '6379', + 'password' => '', + 'database' => '', + ); + + + if ($this->checked_redis === false) { + $c = array( + 'host' => $server[ 'host' ], + ); + + $port = isset($server[ 'port' ]) ? $server[ 'port' ] : ''; + if ($port != '') { + $c[ 'port' ] = $port; + } + + $password = isset($server[ 'password' ]) ? $server[ 'password' ] : ''; + if ($password != '') { + $c[ 'password' ] = $password; + } + + $database = isset($server[ 'database' ]) ? $server[ 'database' ] : ''; + if ($database != '') { + $c[ 'database' ] = $database; + } + + $timeout = isset($server[ 'timeout' ]) ? $server[ 'timeout' ] : ''; + if ($timeout != '') { + $c[ 'timeout' ] = $timeout; + } + + $read_write_timeout = isset($server[ 'read_write_timeout' ]) ? $server[ 'read_write_timeout' ] : ''; + if ($read_write_timeout != '') { + $c[ 'read_write_timeout' ] = $read_write_timeout; + } + + $this->instant = new PredisSoftware($c); + + $this->checked_redis = true; + + if (!$this->instant) { + $this->fallback = true; + return false; + } else { + return true; + } + } + + return true; + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return mixed + */ + public function driver_set($keyword, $value = '', $time = 300, $option = array()) + { + if ($this->connectServer()) { + $value = $this->encode($value); + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true) { + return $this->instant->setex($keyword, $time, $value); + } else { + return $this->instant->setex($keyword, $time, $value); + } + } else { + return $this->backup()->set($keyword, $value, $time, $option); + } + } + + /** + * @param $keyword + * @param array $option + * @return mixed|null + */ + public function driver_get($keyword, $option = array()) + { + if ($this->connectServer()) { + // return null if no caching + // return value if in caching' + $x = $this->instant->get($keyword); + if ($x == false) { + return null; + } else { + + return $this->decode($x); + } + } else { + $this->backup()->get($keyword, $option); + } + } + + /** + * @param $keyword + * @param array $option + */ + public function driver_delete($keyword, $option = array()) + { + + if ($this->connectServer()) { + $this->instant->del($keyword); + } + + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + if ($this->connectServer()) { + $res = array( + 'info' => '', + 'size' => '', + 'data' => $this->instant->info(), + ); + + return $res; + } + + return array(); + + } + + /** + * @param array $option + * @return void + */ + public function driver_clean($option = array()) + { + if ($this->connectServer()) { + $this->instant->flushDB(); + } + + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + if ($this->connectServer()) { + $x = $this->instant->exists($keyword); + return !($x == null); + } else { + return $this->backup()->isExisting($keyword); + } + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/redis.php b/lib/phpfastcache/phpFastCache/Drivers/redis.php new file mode 100644 index 0000000..8ca4195 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/redis.php @@ -0,0 +1,225 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use Redis as RedisSoftware; + +/** + * Class redis + * @package phpFastCache\Drivers + */ +class redis extends DriverAbstract +{ + + /** + * @var bool + */ + public $checked_redis = false; + + /** + * phpFastCache_predis constructor. + * @param array $config + */ + public function __construct($config = array()) + { + $this->setup($config); + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + $this->fallback = true; + } + if (class_exists('Redis')) { + $this->instant = new RedisSoftware(); + } + + } + + /** + * @return bool + */ + public function checkdriver() + { + // Check memcache + if (class_exists('Redis')) { + return true; + } + $this->fallback = true; + return false; + } + + + /** + * @return bool + */ + public function connectServer() + { + + $server = isset($this->config[ 'redis' ]) ? $this->config[ 'redis' ] : array( + 'host' => '127.0.0.1', + 'port' => '6379', + 'password' => '', + 'database' => '', + 'timeout' => '1', + ); + + if ($this->checked_redis === false) { + + $host = $server[ 'host' ]; + + $port = isset($server[ 'port' ]) ? (int)$server[ 'port' ] : ""; + if ($port != '') { + $c[ 'port' ] = $port; + } + + $password = isset($server[ 'password' ]) ? $server[ 'password' ] : ''; + if ($password != '') { + $c[ 'password' ] = $password; + } + + $database = isset($server[ 'database' ]) ? $server[ 'database' ] : ''; + if ($database != '') { + $c[ 'database' ] = $database; + } + + $timeout = isset($server[ 'timeout' ]) ? $server[ 'timeout' ] : ''; + if ($timeout != '') { + $c[ 'timeout' ] = $timeout; + } + + $read_write_timeout = isset($server[ 'read_write_timeout' ]) ? $server[ 'read_write_timeout' ] : ''; + if ($read_write_timeout != '') { + $c[ 'read_write_timeout' ] = $read_write_timeout; + } + + + if (!$this->instant->connect($host, (int)$port, (int)$timeout)) { + $this->checked_redis = true; + $this->fallback = true; + return false; + } else { + if ($database != '') { + $this->instant->select((int)$database); + } + $this->checked_redis = true; + return true; + } + } + + return true; + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return bool + */ + public function driver_set($keyword, $value = '', $time = 300, $option = array()) + { + if ($this->connectServer()) { + $value = $this->encode($value); + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true) { + return $this->instant->set($keyword, $value, + array('xx', 'ex' => $time)); + } else { + return $this->instant->set($keyword, $value, $time); + } + } else { + return $this->backup()->set($keyword, $value, $time, $option); + } + } + + /** + * @param $keyword + * @param array $option + * @return mixed|null + */ + public function driver_get($keyword, $option = array()) + { + if ($this->connectServer()) { + // return null if no caching + // return value if in caching' + $x = $this->instant->get($keyword); + if ($x == false) { + return null; + } else { + + return $this->decode($x); + } + } else { + $this->backup()->get($keyword, $option); + } + + } + + /** + * @param $keyword + * @param array $option + * @return void + */ + public function driver_delete($keyword, $option = array()) + { + if ($this->connectServer()) { + $this->instant->delete($keyword); + } + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + if ($this->connectServer()) { + $res = array( + 'info' => '', + 'size' => '', + 'data' => $this->instant->info(), + ); + + return $res; + } + return array(); + } + + /** + * @param array $option + */ + public function driver_clean($option = array()) + { + if ($this->connectServer()) { + $this->instant->flushDB(); + } + + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + if ($this->connectServer()) { + $x = $this->instant->exists($keyword); + if ($x == null) { + return false; + } else { + return true; + } + } else { + return $this->backup()->isExisting($keyword); + } + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/sqlite.php b/lib/phpfastcache/phpFastCache/Drivers/sqlite.php new file mode 100644 index 0000000..8d45201 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/sqlite.php @@ -0,0 +1,482 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use PDO; +use PDOException; +use phpFastCache\Exceptions\phpFastCacheDriverException; + +/** + * Class sqlite + * @package phpFastCache\Drivers + */ +class sqlite extends DriverAbstract +{ + /** + * + */ + const SQLITE_DIR = 'sqlite'; + /** + * + */ + const INDEXING_FILE = 'indexing'; + + /** + * @var int + */ + public $max_size = 10; // 10 mb + + /** + * @var array + */ + public $instant = array(); + /** + * @var null + */ + public $indexing = null; + /** + * @var string + */ + public $path = ''; + + /** + * @var int + */ + public $currentDB = 1; + + /** + * Init Main Database & Sub Database + * phpFastCache_sqlite constructor. + * @param array $config + * @throws phpFastCacheDriverException + */ + public function __construct($config = array()) + { + /** + * init the path + */ + $this->setup($config); + if (!$this->checkdriver()) { + throw new phpFastCacheDriverException('SQLITE is not installed, cannot continue.'); + } + + if (!file_exists($this->getPath() . '/' . self::SQLITE_DIR)) { + if (!mkdir($this->getPath() . '/' . self::SQLITE_DIR, $this->__setChmodAuto(), true)) { + $this->fallback = true; + } + } + $this->path = $this->getPath() . '/' . self::SQLITE_DIR; + } + + /** + * INIT NEW DB + * @param \PDO $db + */ + public function initDB(PDO $db) + { + $db->exec('drop table if exists "caching"'); + $db->exec('CREATE TABLE "caching" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "keyword" VARCHAR UNIQUE, "object" BLOB, "exp" INTEGER)'); + $db->exec('CREATE UNIQUE INDEX "cleanup" ON "caching" ("keyword","exp")'); + $db->exec('CREATE INDEX "exp" ON "caching" ("exp")'); + $db->exec('CREATE UNIQUE INDEX "keyword" ON "caching" ("keyword")'); + } + + /** + * INIT Indexing DB + * @param \PDO $db + */ + public function initIndexing(PDO $db) + { + + // delete everything before reset indexing + $dir = opendir($this->path); + while ($file = readdir($dir)) { + if ($file != '.' && $file != '..' && $file != 'indexing' && $file != 'dbfastcache') { + unlink($this->path . '/' . $file); + } + } + + $db->exec('drop table if exists "balancing"'); + $db->exec('CREATE TABLE "balancing" ("keyword" VARCHAR PRIMARY KEY NOT NULL UNIQUE, "db" INTEGER)'); + $db->exec('CREATE INDEX "db" ON "balancing" ("db")'); + $db->exec('CREATE UNIQUE INDEX "lookup" ON "balancing" ("keyword")'); + + } + + /** + * INIT Instant DB + * Return Database of Keyword + * @param $keyword + * @return int + */ + public function indexing($keyword) + { + if ($this->indexing == null) { + $createTable = false; + if (!file_exists($this->path . '/indexing')) { + $createTable = true; + } + + $PDO = new PDO("sqlite:" . $this->path . '/' . self::INDEXING_FILE); + $PDO->setAttribute(PDO::ATTR_ERRMODE, + PDO::ERRMODE_EXCEPTION); + + if ($createTable == true) { + $this->initIndexing($PDO); + } + $this->indexing = $PDO; + unset($PDO); + + $stm = $this->indexing->prepare("SELECT MAX(`db`) as `db` FROM `balancing`"); + $stm->execute(); + $row = $stm->fetch(PDO::FETCH_ASSOC); + if (!isset($row[ 'db' ])) { + $db = 1; + } elseif ($row[ 'db' ] <= 1) { + $db = 1; + } else { + $db = $row[ 'db' ]; + } + + // check file size + + $size = file_exists($this->path . '/db' . $db) ? filesize($this->path . '/db' . $db) : 1; + $size = round($size / 1024 / 1024, 1); + + + if ($size > $this->max_size) { + $db = $db + 1; + } + $this->currentDB = $db; + + } + + // look for keyword + $stm = $this->indexing->prepare("SELECT * FROM `balancing` WHERE `keyword`=:keyword LIMIT 1"); + $stm->execute(array( + ':keyword' => $keyword, + )); + $row = $stm->fetch(PDO::FETCH_ASSOC); + if (isset($row[ 'db' ]) && $row[ 'db' ] != '') { + $db = $row[ 'db' ]; + } else { + /* + * Insert new to Indexing + */ + $db = $this->currentDB; + $stm = $this->indexing->prepare("INSERT INTO `balancing` (`keyword`,`db`) VALUES(:keyword, :db)"); + $stm->execute(array( + ':keyword' => $keyword, + ':db' => $db, + )); + } + + return $db; + } + + /** + * @param $keyword + * @param bool $reset + * @return mixed + */ + public function db($keyword, $reset = false) + { + /** + * Default is fastcache + */ + $instant = $this->indexing($keyword); + + /** + * init instant + */ + if (!isset($this->instant[ $instant ])) { + // check DB Files ready or not + $createTable = false; + if (!file_exists($this->path . '/db' . $instant) || $reset == true) { + $createTable = true; + } + $PDO = new PDO('sqlite:' . $this->path . '/db' . $instant); + $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + if ($createTable == true) { + $this->initDB($PDO); + } + + $this->instant[ $instant ] = $PDO; + unset($PDO); + + } + + return $this->instant[ $instant ]; + } + + /** + * @return bool + */ + public function checkdriver() + { + if (extension_loaded('pdo_sqlite') && is_writable($this->getPath())) { + return true; + } + $this->fallback = true; + return false; + } + + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return bool + */ + public function driver_set( + $keyword, + $value = '', + $time = 300, + $option = array() + ) { + $skipExisting = isset($option[ 'skipExisting' ]) ? $option[ 'skipExisting' ] : false; + $toWrite = true; + + // check in cache first + $in_cache = $this->get($keyword, $option); + + if ($skipExisting == true) { + if ($in_cache == null) { + $toWrite = true; + } else { + $toWrite = false; + } + } + + if ($toWrite == true) { + try { + $stm = $this->db($keyword) + ->prepare("INSERT OR REPLACE INTO `caching` (`keyword`,`object`,`exp`) values(:keyword,:object,:exp)"); + $stm->execute(array( + ':keyword' => $keyword, + ':object' => $this->encode($value), + ':exp' => time() + (int)$time, + )); + + return true; + } catch (\PDOException $e) { + + try { + $stm = $this->db($keyword, true) + ->prepare("INSERT OR REPLACE INTO `caching` (`keyword`,`object`,`exp`) values(:keyword,:object,:exp)"); + $stm->execute(array( + ':keyword' => $keyword, + ':object' => $this->encode($value), + ':exp' => time() + (int)$time, + )); + } catch (PDOException $e) { + return false; + } + } + } + return false; + } + + /** + * @param $keyword + * @param array $option + * @return mixed|null + */ + public function driver_get($keyword, $option = array()) + { + // return null if no caching + // return value if in caching + try { + $stm = $this->db($keyword) + ->prepare("SELECT * FROM `caching` WHERE `keyword`=:keyword LIMIT 1"); + $stm->execute(array( + ':keyword' => $keyword, + )); + $row = $stm->fetch(PDO::FETCH_ASSOC); + + } catch (PDOException $e) { + try { + $stm = $this->db($keyword, true) + ->prepare("SELECT * FROM `caching` WHERE `keyword`=:keyword LIMIT 1"); + $stm->execute(array( + ':keyword' => $keyword, + )); + $row = $stm->fetch(PDO::FETCH_ASSOC); + } catch (PDOException $e) { + return null; + } + + } + + if ($this->isExpired($row)) { + $this->deleteRow($row); + return null; + } + + if (isset($row[ 'id' ])) { + $data = $this->decode($row[ 'object' ]); + return $data; + } + + return null; + } + + /** + * @param $row + * @return bool + */ + public function isExpired($row) + { + if (isset($row[ 'exp' ]) && time() >= $row[ 'exp' ]) { + return true; + } + + return false; + } + + /** + * @param $row + * @return bool + */ + public function deleteRow($row) + { + try { + $stm = $this->db($row[ 'keyword' ]) + ->prepare("DELETE FROM `caching` WHERE (`id`=:id) OR (`exp` <= :U) "); + $stm->execute(array( + ':id' => $row[ 'id' ], + ':U' => time(), + )); + } catch (PDOException $e) { + return false; + } + } + + /** + * @param $keyword + * @param array $option + * @return bool + */ + public function driver_delete($keyword, $option = array()) + { + try { + $stm = $this->db($keyword) + ->prepare("DELETE FROM `caching` WHERE (`keyword`=:keyword) OR (`exp` <= :U)"); + $stm->execute(array( + ':keyword' => $keyword, + ':U' => time(), + )); + } catch (PDOException $e) { + return false; + } + } + + /** + * Return total cache size + auto removed expired entries + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + $res = array( + 'info' => '', + 'size' => '', + 'data' => '', + ); + $total = 0; + $optimized = 0; + + $dir = opendir($this->path); + while ($file = readdir($dir)) { + if ($file != '.' && $file != '..') { + $file_path = $this->path . "/" . $file; + $size = filesize($file_path); + $total = $total + $size; + + try { + $PDO = new PDO("sqlite:" . $file_path); + $PDO->setAttribute(PDO::ATTR_ERRMODE, + PDO::ERRMODE_EXCEPTION); + + $stm = $PDO->prepare("DELETE FROM `caching` WHERE `exp` <= :U"); + $stm->execute(array( + ':U' => date('U'), + )); + + $PDO->exec('VACUUM;'); + $size = filesize($file_path); + $optimized = $optimized + $size; + } catch (PDOException $e) { + $size = 0; + $optimized = 0; + } + + + } + } + $res[ 'size' ] = $optimized; + $res[ 'info' ] = array( + 'total before removing expired entries [bytes]' => $total, + 'optimized after removing expired entries [bytes]' => $optimized, + ); + + return $res; + } + + /** + * @param array $option + * @return void + */ + public function driver_clean($option = array()) + { + // close connection + $this->instant = array(); + $this->indexing = null; + + // delete everything before reset indexing + $dir = opendir($this->path); + while ($file = readdir($dir)) { + if ($file != '.' && $file != '..') { + unlink($this->path . '/' . $file); + } + } + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + try { + $stm = $this->db($keyword) + ->prepare("SELECT COUNT(`id`) as `total` FROM `caching` WHERE `keyword`=:keyword"); + $stm->execute(array( + ':keyword' => $keyword, + )); + $data = $stm->fetch(PDO::FETCH_ASSOC); + if ($data[ 'total' ] >= 1) { + return true; + } else { + return false; + } + } catch (PDOException $e) { + return false; + } + } +} diff --git a/lib/phpfastcache/phpFastCache/Drivers/ssdb.php b/lib/phpfastcache/phpFastCache/Drivers/ssdb.php new file mode 100644 index 0000000..84830cc --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/ssdb.php @@ -0,0 +1,191 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; + +/** + * Class ssdb + * @package phpFastCache\Drivers + */ +class ssdb extends DriverAbstract +{ + + /** + * @var bool + */ + private $checked_ssdb = false; + + /** + * phpFastCache_ssdb constructor. + * @param array $config + */ + public function __construct($config = array()) + { + $this->setup($config); + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + $this->fallback = true; + } + } + + /** + * @return bool + */ + public function checkdriver() + { + // Check memcache + $this->required_extension('SSDB'); + if (class_exists('SimpleSSDB')) { + return true; + } + $this->fallback = true; + return false; + } + + + /** + * @return bool + */ + public function connectServer() + { + + $server = isset($this->config[ 'ssdb' ]) ? $this->config[ 'ssdb' ] : array( + 'host' => "127.0.0.1", + 'port' => 8888, + 'password' => '', + 'timeout' => 2000, + ); + + if ($this->checked_ssdb === false) { + $host = $server[ 'host' ]; + $port = isset($server[ 'port' ]) ? (int)$server[ 'port' ] : 8888; + $password = isset($server[ 'password' ]) ? $server[ 'password' ] : ''; + $timeout = !empty($server[ 'timeout' ]) ? (int)$server[ 'timeout' ] : 2000; + $this->instant = new \SimpleSSDB($host, $port, $timeout); + if (!empty($password)) { + $this->instant->auth($password); + } + $this->checked_ssdb = true; + if (!$this->instant) { + $this->fallback = true; + return false; + } else { + return true; + } + } + + return true; + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return bool + */ + public function driver_set($keyword, $value = '', $time = 300, $option = array()) + { + if ($this->connectServer()) { + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true) { + $x = $this->instant->get($keyword); + if ($x === false) { + return false; + } elseif (!is_null($x)) { + return true; + } + } + $value = $this->encode($value); + return $this->instant->setx($keyword, $value, $time); + } else { + return $this->backup()->set($keyword, $value, $time, $option); + } + } + + /** + * @param $keyword + * @param array $option + * @return mixed|null + */ + public function driver_get($keyword, $option = array()) + { + if ($this->connectServer()) { + // return null if no caching + // return value if in caching' + $x = $this->instant->get($keyword); + if ($x == false) { + return null; + } else { + return $this->decode($x); + } + } else { + $this->backup()->get($keyword, $option); + } + } + + /** + * @param $keyword + * @param array $option + */ + public function driver_delete($keyword, $option = array()) + { + if ($this->connectServer()) { + $this->instant->del($keyword); + } + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + if ($this->connectServer()) { + $res = array( + 'info' => '', + 'size' => $this->instant->dbsize(), + 'data' => $this->instant->info(), + ); + + return $res; + } + + return array(); + } + + /** + * @param array $option + * @return bool + */ + public function driver_clean($option = array()) + { + //Is not supported, only support command line operations + return false; + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + if ($this->connectServer()) { + $x = $this->instant->exists($keyword); + return !($x == null); + } else { + return $this->backup()->isExisting($keyword); + } + } +} diff --git a/lib/phpfastcache/phpFastCache/Drivers/wincache.php b/lib/phpfastcache/phpFastCache/Drivers/wincache.php new file mode 100644 index 0000000..44a6204 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/wincache.php @@ -0,0 +1,133 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; + +/** + * Class wincache + * @package phpFastCache\Drivers + */ +class wincache extends DriverAbstract +{ + + /** + * phpFastCache_wincache constructor. + * @param array $config + */ + public function __construct($config = array()) + { + $this->setup($config); + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + $this->fallback = true; + } + + } + + /** + * @return bool + */ + public function checkdriver() + { + if (extension_loaded('wincache') && function_exists('wincache_ucache_set')) { + return true; + } + $this->fallback = true; + return false; + } + + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return bool + */ + public function driver_set($keyword, $value = "", $time = 300, $option = array()) + { + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true) { + return wincache_ucache_add($keyword, $value, $time); + } else { + return wincache_ucache_set($keyword, $value, $time); + } + } + + /** + * @param $keyword + * @param array $option + * @return mixed|null + */ + public function driver_get($keyword, $option = array()) + { + // return null if no caching + // return value if in caching + + $x = wincache_ucache_get($keyword, $suc); + + if ($suc == false) { + return null; + } else { + return $x; + } + } + + /** + * @param $keyword + * @param array $option + * @return bool + */ + public function driver_delete($keyword, $option = array()) + { + return wincache_ucache_delete($keyword); + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + $res = array( + 'info' => '', + 'size' => '', + 'data' => wincache_scache_info(), + ); + return $res; + } + + /** + * @param array $option + * @return bool + */ + public function driver_clean($option = array()) + { + wincache_ucache_clear(); + return true; + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + if (wincache_ucache_exists($keyword)) { + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Drivers/xcache.php b/lib/phpfastcache/phpFastCache/Drivers/xcache.php new file mode 100644 index 0000000..3b2a675 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Drivers/xcache.php @@ -0,0 +1,141 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Drivers; + +use phpFastCache\Core\DriverAbstract; +use Exception; + +/** + * Class xcache + * @package phpFastCache\Drivers + */ +class xcache extends DriverAbstract +{ + + /** + * phpFastCache_xcache constructor. + * @param array $config + */ + public function __construct($config = array()) + { + $this->setup($config); + if (!$this->checkdriver() && !isset($config[ 'skipError' ])) { + $this->fallback = true; + } + + } + + /** + * @return bool + */ + public function checkdriver() + { + // Check xcache + if (extension_loaded('xcache') && function_exists('xcache_get')) { + return true; + } + $this->fallback = true; + return false; + + } + + /** + * @param $keyword + * @param string $value + * @param int $time + * @param array $option + * @return bool + */ + public function driver_set($keyword, $value = "", $time = 300, $option = array()) + { + + if (isset($option[ 'skipExisting' ]) && $option[ 'skipExisting' ] == true) { + if (!$this->isExisting($keyword)) { + return xcache_set($keyword, serialize($value), $time); + } + } else { + return xcache_set($keyword, serialize($value), $time); + } + return false; + } + + /** + * @param $keyword + * @param array $option + * @return mixed|null + */ + public function driver_get($keyword, $option = array()) + { + // return null if no caching + // return value if in caching + $data = unserialize(xcache_get($keyword)); + if ($data === false || $data == '') { + return null; + } + return $data; + } + + /** + * @param $keyword + * @param array $option + * @return bool + */ + public function driver_delete($keyword, $option = array()) + { + return xcache_unset($keyword); + } + + /** + * @param array $option + * @return array + */ + public function driver_stats($option = array()) + { + $res = array( + 'info' => '', + 'size' => '', + 'data' => '', + ); + + try { + $res[ 'data' ] = xcache_list(XC_TYPE_VAR, 100); + } catch (Exception $e) { + $res[ 'data' ] = array(); + } + return $res; + } + + /** + * @param array $option + * @return bool + */ + public function driver_clean($option = array()) + { + $cnt = xcache_count(XC_TYPE_VAR); + for ($i = 0; $i < $cnt; $i++) { + xcache_clear_cache(XC_TYPE_VAR, $i); + } + return true; + } + + /** + * @param $keyword + * @return bool + */ + public function driver_isExisting($keyword) + { + return xcache_isset($keyword); + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Exceptions/phpFastCacheCoreException.php b/lib/phpfastcache/phpFastCache/Exceptions/phpFastCacheCoreException.php new file mode 100644 index 0000000..6314b6e --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Exceptions/phpFastCacheCoreException.php @@ -0,0 +1,26 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Exceptions; + +use \Exception; + +/** + * Class phpFastCacheCoreException + * @package phpFastCache\Exceptions + */ +class phpFastCacheCoreException extends Exception +{ + +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Exceptions/phpFastCacheDriverException.php b/lib/phpfastcache/phpFastCache/Exceptions/phpFastCacheDriverException.php new file mode 100644 index 0000000..5f44b4a --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Exceptions/phpFastCacheDriverException.php @@ -0,0 +1,26 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Exceptions; + +use \Exception; + +/** + * Class phpFastCacheDriverException + * @package phpFastCache\Exceptions + */ +class phpFastCacheDriverException extends Exception +{ + +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Plugins/CronClearFiles.php b/lib/phpfastcache/phpFastCache/Plugins/CronClearFiles.php new file mode 100644 index 0000000..11d80eb --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Plugins/CronClearFiles.php @@ -0,0 +1,33 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\plugins; + +use phpFastCache\CacheManager; + +// Setup your cronjob to run this file every +// 30 mins - 60 mins to help clean up +// the expired files faster + +require_once (__DIR__ . "/../phpFastCache.php"); + +$setup = array( + "path" => "/your_path/to_clean/" +); + +$cache = CacheManager::Files($setup); + +// clean up expired files cache every hour +// For now only "files" drivers is supported +$cache->autoCleanExpired(3600*1); \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Util/Languages.php b/lib/phpfastcache/phpFastCache/Util/Languages.php new file mode 100644 index 0000000..484c590 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Util/Languages.php @@ -0,0 +1,47 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +namespace phpFastCache\Util; +use phpFastCache\Exceptions\phpFastCacheCoreException; + + +/** + * Class Languages + * @author Khoa Bui (khoaofgod) http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ +class Languages +{ + public static function setEncoding($encoding = 'UTF-8', $language = null) + { + if ($language === null || !in_array($language, array('uni', 'Japanese', 'ja', 'English', 'en'), true)) { + $language = 'uni'; + } + switch(strtoupper($encoding)) + { + case 'UTF-8': + if(extension_loaded("mbstring")) { + mb_internal_encoding($encoding); + mb_http_output($encoding); + mb_http_input($encoding); + mb_language($language); + mb_regex_encoding($encoding); + } else { + throw new phpFastCacheCoreException("MB String need to be installed for Unicode Encoding"); + } + break; + } + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/Util/Legacy.php b/lib/phpfastcache/phpFastCache/Util/Legacy.php new file mode 100644 index 0000000..a1c58f0 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/Util/Legacy.php @@ -0,0 +1,43 @@ +".$tmp[0]." = ".$path." BY {$allowed_path}"; + self::$stores[$index] = true; + return true; + } + } + self::$stores[$index] = false; + } else { + return self::$stores[$index]; + } + return false; + } + return true; + } +} \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/index.html b/lib/phpfastcache/phpFastCache/index.html new file mode 100644 index 0000000..4304a89 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/index.html @@ -0,0 +1 @@ +Visit www.phpfastcache.com \ No newline at end of file diff --git a/lib/phpfastcache/phpFastCache/phpFastCache.php b/lib/phpfastcache/phpFastCache/phpFastCache.php new file mode 100644 index 0000000..db1f066 --- /dev/null +++ b/lib/phpfastcache/phpFastCache/phpFastCache.php @@ -0,0 +1,55 @@ + http://www.phpfastcache.com + * @author Georges.L (Geolim4) + * + */ + +use phpFastCache\CacheManager; +define('PHP_EXT', substr(strrchr(__FILE__, '.'), 1)); + +if(!defined("PHPFASTCACHE_LEGACY")) { + /** + * Register Autoload + */ + spl_autoload_register(function ($entity) { + // Explode is faster than substr & strstr also more control + $module = explode('\\',$entity,2); + if ($module[0] !== 'phpFastCache') { + /** + * Not a part of phpFastCache file + * then we return here. + */ + return; + } + + $entity = str_replace('\\', '/', $module[1]); + $path = __DIR__ . '/' . $entity . '.' . PHP_EXT; + if (is_readable($path)) { + require_once $path; + } + }); + +} else { + require_once __DIR__.'/Util/Legacy.php'; +} + +/** + * phpFastCache() Full alias + * @param string $storage + * @param array $config + * @return mixed + */ +if (!function_exists("phpFastCache")) { + function phpFastCache($storage = 'auto', $config = array()) + { + return CacheManager::getInstance($storage, $config); + } +} diff --git a/lib/ts3phpframework/LICENSE b/lib/ts3phpframework/LICENSE new file mode 100644 index 0000000..70566f2 --- /dev/null +++ b/lib/ts3phpframework/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/lib/ts3phpframework/images/flags/ad.png b/lib/ts3phpframework/images/flags/ad.png new file mode 100644 index 0000000..625ca84 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ad.png differ diff --git a/lib/ts3phpframework/images/flags/ae.png b/lib/ts3phpframework/images/flags/ae.png new file mode 100644 index 0000000..ef3a1ec Binary files /dev/null and b/lib/ts3phpframework/images/flags/ae.png differ diff --git a/lib/ts3phpframework/images/flags/af.png b/lib/ts3phpframework/images/flags/af.png new file mode 100644 index 0000000..a4742e2 Binary files /dev/null and b/lib/ts3phpframework/images/flags/af.png differ diff --git a/lib/ts3phpframework/images/flags/ag.png b/lib/ts3phpframework/images/flags/ag.png new file mode 100644 index 0000000..556d550 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ag.png differ diff --git a/lib/ts3phpframework/images/flags/ai.png b/lib/ts3phpframework/images/flags/ai.png new file mode 100644 index 0000000..74ed29d Binary files /dev/null and b/lib/ts3phpframework/images/flags/ai.png differ diff --git a/lib/ts3phpframework/images/flags/al.png b/lib/ts3phpframework/images/flags/al.png new file mode 100644 index 0000000..92354cb Binary files /dev/null and b/lib/ts3phpframework/images/flags/al.png differ diff --git a/lib/ts3phpframework/images/flags/am.png b/lib/ts3phpframework/images/flags/am.png new file mode 100644 index 0000000..344a2a8 Binary files /dev/null and b/lib/ts3phpframework/images/flags/am.png differ diff --git a/lib/ts3phpframework/images/flags/an.png b/lib/ts3phpframework/images/flags/an.png new file mode 100644 index 0000000..633e4b8 Binary files /dev/null and b/lib/ts3phpframework/images/flags/an.png differ diff --git a/lib/ts3phpframework/images/flags/ao.png b/lib/ts3phpframework/images/flags/ao.png new file mode 100644 index 0000000..bcbd1d6 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ao.png differ diff --git a/lib/ts3phpframework/images/flags/ar.png b/lib/ts3phpframework/images/flags/ar.png new file mode 100644 index 0000000..e5ef8f1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ar.png differ diff --git a/lib/ts3phpframework/images/flags/as.png b/lib/ts3phpframework/images/flags/as.png new file mode 100644 index 0000000..32f30e4 Binary files /dev/null and b/lib/ts3phpframework/images/flags/as.png differ diff --git a/lib/ts3phpframework/images/flags/at.png b/lib/ts3phpframework/images/flags/at.png new file mode 100644 index 0000000..0f15f34 Binary files /dev/null and b/lib/ts3phpframework/images/flags/at.png differ diff --git a/lib/ts3phpframework/images/flags/au.png b/lib/ts3phpframework/images/flags/au.png new file mode 100644 index 0000000..a01389a Binary files /dev/null and b/lib/ts3phpframework/images/flags/au.png differ diff --git a/lib/ts3phpframework/images/flags/aw.png b/lib/ts3phpframework/images/flags/aw.png new file mode 100644 index 0000000..a3579c2 Binary files /dev/null and b/lib/ts3phpframework/images/flags/aw.png differ diff --git a/lib/ts3phpframework/images/flags/ax.png b/lib/ts3phpframework/images/flags/ax.png new file mode 100644 index 0000000..1eea80a Binary files /dev/null and b/lib/ts3phpframework/images/flags/ax.png differ diff --git a/lib/ts3phpframework/images/flags/az.png b/lib/ts3phpframework/images/flags/az.png new file mode 100644 index 0000000..4ee9fe5 Binary files /dev/null and b/lib/ts3phpframework/images/flags/az.png differ diff --git a/lib/ts3phpframework/images/flags/ba.png b/lib/ts3phpframework/images/flags/ba.png new file mode 100644 index 0000000..c774992 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ba.png differ diff --git a/lib/ts3phpframework/images/flags/bb.png b/lib/ts3phpframework/images/flags/bb.png new file mode 100644 index 0000000..0df19c7 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bb.png differ diff --git a/lib/ts3phpframework/images/flags/bd.png b/lib/ts3phpframework/images/flags/bd.png new file mode 100644 index 0000000..076a8bf Binary files /dev/null and b/lib/ts3phpframework/images/flags/bd.png differ diff --git a/lib/ts3phpframework/images/flags/be.png b/lib/ts3phpframework/images/flags/be.png new file mode 100644 index 0000000..d86ebc8 Binary files /dev/null and b/lib/ts3phpframework/images/flags/be.png differ diff --git a/lib/ts3phpframework/images/flags/bf.png b/lib/ts3phpframework/images/flags/bf.png new file mode 100644 index 0000000..ab5ce8f Binary files /dev/null and b/lib/ts3phpframework/images/flags/bf.png differ diff --git a/lib/ts3phpframework/images/flags/bg.png b/lib/ts3phpframework/images/flags/bg.png new file mode 100644 index 0000000..0469f06 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bg.png differ diff --git a/lib/ts3phpframework/images/flags/bh.png b/lib/ts3phpframework/images/flags/bh.png new file mode 100644 index 0000000..ea8ce68 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bh.png differ diff --git a/lib/ts3phpframework/images/flags/bi.png b/lib/ts3phpframework/images/flags/bi.png new file mode 100644 index 0000000..5cc2e30 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bi.png differ diff --git a/lib/ts3phpframework/images/flags/bj.png b/lib/ts3phpframework/images/flags/bj.png new file mode 100644 index 0000000..1cc8b45 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bj.png differ diff --git a/lib/ts3phpframework/images/flags/bl.png b/lib/ts3phpframework/images/flags/bl.png new file mode 100644 index 0000000..8332c4e Binary files /dev/null and b/lib/ts3phpframework/images/flags/bl.png differ diff --git a/lib/ts3phpframework/images/flags/bm.png b/lib/ts3phpframework/images/flags/bm.png new file mode 100644 index 0000000..c0c7aea Binary files /dev/null and b/lib/ts3phpframework/images/flags/bm.png differ diff --git a/lib/ts3phpframework/images/flags/bn.png b/lib/ts3phpframework/images/flags/bn.png new file mode 100644 index 0000000..8fb0984 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bn.png differ diff --git a/lib/ts3phpframework/images/flags/bo.png b/lib/ts3phpframework/images/flags/bo.png new file mode 100644 index 0000000..ce7ba52 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bo.png differ diff --git a/lib/ts3phpframework/images/flags/br.png b/lib/ts3phpframework/images/flags/br.png new file mode 100644 index 0000000..9b1a553 Binary files /dev/null and b/lib/ts3phpframework/images/flags/br.png differ diff --git a/lib/ts3phpframework/images/flags/bs.png b/lib/ts3phpframework/images/flags/bs.png new file mode 100644 index 0000000..639fa6c Binary files /dev/null and b/lib/ts3phpframework/images/flags/bs.png differ diff --git a/lib/ts3phpframework/images/flags/bt.png b/lib/ts3phpframework/images/flags/bt.png new file mode 100644 index 0000000..1d512df Binary files /dev/null and b/lib/ts3phpframework/images/flags/bt.png differ diff --git a/lib/ts3phpframework/images/flags/bv.png b/lib/ts3phpframework/images/flags/bv.png new file mode 100644 index 0000000..160b6b5 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bv.png differ diff --git a/lib/ts3phpframework/images/flags/bw.png b/lib/ts3phpframework/images/flags/bw.png new file mode 100644 index 0000000..fcb1039 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bw.png differ diff --git a/lib/ts3phpframework/images/flags/by.png b/lib/ts3phpframework/images/flags/by.png new file mode 100644 index 0000000..504774e Binary files /dev/null and b/lib/ts3phpframework/images/flags/by.png differ diff --git a/lib/ts3phpframework/images/flags/bz.png b/lib/ts3phpframework/images/flags/bz.png new file mode 100644 index 0000000..be63ee1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/bz.png differ diff --git a/lib/ts3phpframework/images/flags/ca.png b/lib/ts3phpframework/images/flags/ca.png new file mode 100644 index 0000000..1f20419 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ca.png differ diff --git a/lib/ts3phpframework/images/flags/cc.png b/lib/ts3phpframework/images/flags/cc.png new file mode 100644 index 0000000..aed3d3b Binary files /dev/null and b/lib/ts3phpframework/images/flags/cc.png differ diff --git a/lib/ts3phpframework/images/flags/cd.png b/lib/ts3phpframework/images/flags/cd.png new file mode 100644 index 0000000..5e48942 Binary files /dev/null and b/lib/ts3phpframework/images/flags/cd.png differ diff --git a/lib/ts3phpframework/images/flags/cf.png b/lib/ts3phpframework/images/flags/cf.png new file mode 100644 index 0000000..da687bd Binary files /dev/null and b/lib/ts3phpframework/images/flags/cf.png differ diff --git a/lib/ts3phpframework/images/flags/cg.png b/lib/ts3phpframework/images/flags/cg.png new file mode 100644 index 0000000..a859792 Binary files /dev/null and b/lib/ts3phpframework/images/flags/cg.png differ diff --git a/lib/ts3phpframework/images/flags/ch.png b/lib/ts3phpframework/images/flags/ch.png new file mode 100644 index 0000000..242ec01 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ch.png differ diff --git a/lib/ts3phpframework/images/flags/ci.png b/lib/ts3phpframework/images/flags/ci.png new file mode 100644 index 0000000..3f2c62e Binary files /dev/null and b/lib/ts3phpframework/images/flags/ci.png differ diff --git a/lib/ts3phpframework/images/flags/ck.png b/lib/ts3phpframework/images/flags/ck.png new file mode 100644 index 0000000..746d3d6 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ck.png differ diff --git a/lib/ts3phpframework/images/flags/cl.png b/lib/ts3phpframework/images/flags/cl.png new file mode 100644 index 0000000..29c6d61 Binary files /dev/null and b/lib/ts3phpframework/images/flags/cl.png differ diff --git a/lib/ts3phpframework/images/flags/cm.png b/lib/ts3phpframework/images/flags/cm.png new file mode 100644 index 0000000..f65c5bd Binary files /dev/null and b/lib/ts3phpframework/images/flags/cm.png differ diff --git a/lib/ts3phpframework/images/flags/cn.png b/lib/ts3phpframework/images/flags/cn.png new file mode 100644 index 0000000..8914414 Binary files /dev/null and b/lib/ts3phpframework/images/flags/cn.png differ diff --git a/lib/ts3phpframework/images/flags/co.png b/lib/ts3phpframework/images/flags/co.png new file mode 100644 index 0000000..a118ff4 Binary files /dev/null and b/lib/ts3phpframework/images/flags/co.png differ diff --git a/lib/ts3phpframework/images/flags/cr.png b/lib/ts3phpframework/images/flags/cr.png new file mode 100644 index 0000000..c7a3731 Binary files /dev/null and b/lib/ts3phpframework/images/flags/cr.png differ diff --git a/lib/ts3phpframework/images/flags/cs.png b/lib/ts3phpframework/images/flags/cs.png new file mode 100644 index 0000000..8254790 Binary files /dev/null and b/lib/ts3phpframework/images/flags/cs.png differ diff --git a/lib/ts3phpframework/images/flags/cu.png b/lib/ts3phpframework/images/flags/cu.png new file mode 100644 index 0000000..083f1d6 Binary files /dev/null and b/lib/ts3phpframework/images/flags/cu.png differ diff --git a/lib/ts3phpframework/images/flags/cv.png b/lib/ts3phpframework/images/flags/cv.png new file mode 100644 index 0000000..a63f7ea Binary files /dev/null and b/lib/ts3phpframework/images/flags/cv.png differ diff --git a/lib/ts3phpframework/images/flags/cw.png b/lib/ts3phpframework/images/flags/cw.png new file mode 100644 index 0000000..2a0a66c Binary files /dev/null and b/lib/ts3phpframework/images/flags/cw.png differ diff --git a/lib/ts3phpframework/images/flags/cx.png b/lib/ts3phpframework/images/flags/cx.png new file mode 100644 index 0000000..48e31ad Binary files /dev/null and b/lib/ts3phpframework/images/flags/cx.png differ diff --git a/lib/ts3phpframework/images/flags/cy.png b/lib/ts3phpframework/images/flags/cy.png new file mode 100644 index 0000000..5b1ad6c Binary files /dev/null and b/lib/ts3phpframework/images/flags/cy.png differ diff --git a/lib/ts3phpframework/images/flags/cz.png b/lib/ts3phpframework/images/flags/cz.png new file mode 100644 index 0000000..c8403dd Binary files /dev/null and b/lib/ts3phpframework/images/flags/cz.png differ diff --git a/lib/ts3phpframework/images/flags/de.png b/lib/ts3phpframework/images/flags/de.png new file mode 100644 index 0000000..ac4a977 Binary files /dev/null and b/lib/ts3phpframework/images/flags/de.png differ diff --git a/lib/ts3phpframework/images/flags/dj.png b/lib/ts3phpframework/images/flags/dj.png new file mode 100644 index 0000000..582af36 Binary files /dev/null and b/lib/ts3phpframework/images/flags/dj.png differ diff --git a/lib/ts3phpframework/images/flags/dk.png b/lib/ts3phpframework/images/flags/dk.png new file mode 100644 index 0000000..e2993d3 Binary files /dev/null and b/lib/ts3phpframework/images/flags/dk.png differ diff --git a/lib/ts3phpframework/images/flags/dm.png b/lib/ts3phpframework/images/flags/dm.png new file mode 100644 index 0000000..5fbffcb Binary files /dev/null and b/lib/ts3phpframework/images/flags/dm.png differ diff --git a/lib/ts3phpframework/images/flags/do.png b/lib/ts3phpframework/images/flags/do.png new file mode 100644 index 0000000..5a04932 Binary files /dev/null and b/lib/ts3phpframework/images/flags/do.png differ diff --git a/lib/ts3phpframework/images/flags/dz.png b/lib/ts3phpframework/images/flags/dz.png new file mode 100644 index 0000000..335c239 Binary files /dev/null and b/lib/ts3phpframework/images/flags/dz.png differ diff --git a/lib/ts3phpframework/images/flags/ec.png b/lib/ts3phpframework/images/flags/ec.png new file mode 100644 index 0000000..0caa0b1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ec.png differ diff --git a/lib/ts3phpframework/images/flags/ee.png b/lib/ts3phpframework/images/flags/ee.png new file mode 100644 index 0000000..0c82efb Binary files /dev/null and b/lib/ts3phpframework/images/flags/ee.png differ diff --git a/lib/ts3phpframework/images/flags/eg.png b/lib/ts3phpframework/images/flags/eg.png new file mode 100644 index 0000000..8a3f7a1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/eg.png differ diff --git a/lib/ts3phpframework/images/flags/eh.png b/lib/ts3phpframework/images/flags/eh.png new file mode 100644 index 0000000..90a1195 Binary files /dev/null and b/lib/ts3phpframework/images/flags/eh.png differ diff --git a/lib/ts3phpframework/images/flags/er.png b/lib/ts3phpframework/images/flags/er.png new file mode 100644 index 0000000..13065ae Binary files /dev/null and b/lib/ts3phpframework/images/flags/er.png differ diff --git a/lib/ts3phpframework/images/flags/es.png b/lib/ts3phpframework/images/flags/es.png new file mode 100644 index 0000000..c2de2d7 Binary files /dev/null and b/lib/ts3phpframework/images/flags/es.png differ diff --git a/lib/ts3phpframework/images/flags/et.png b/lib/ts3phpframework/images/flags/et.png new file mode 100644 index 0000000..2e893fa Binary files /dev/null and b/lib/ts3phpframework/images/flags/et.png differ diff --git a/lib/ts3phpframework/images/flags/fi.png b/lib/ts3phpframework/images/flags/fi.png new file mode 100644 index 0000000..14ec091 Binary files /dev/null and b/lib/ts3phpframework/images/flags/fi.png differ diff --git a/lib/ts3phpframework/images/flags/fj.png b/lib/ts3phpframework/images/flags/fj.png new file mode 100644 index 0000000..cee9988 Binary files /dev/null and b/lib/ts3phpframework/images/flags/fj.png differ diff --git a/lib/ts3phpframework/images/flags/fk.png b/lib/ts3phpframework/images/flags/fk.png new file mode 100644 index 0000000..ceaeb27 Binary files /dev/null and b/lib/ts3phpframework/images/flags/fk.png differ diff --git a/lib/ts3phpframework/images/flags/fm.png b/lib/ts3phpframework/images/flags/fm.png new file mode 100644 index 0000000..066bb24 Binary files /dev/null and b/lib/ts3phpframework/images/flags/fm.png differ diff --git a/lib/ts3phpframework/images/flags/fo.png b/lib/ts3phpframework/images/flags/fo.png new file mode 100644 index 0000000..cbceb80 Binary files /dev/null and b/lib/ts3phpframework/images/flags/fo.png differ diff --git a/lib/ts3phpframework/images/flags/fr.png b/lib/ts3phpframework/images/flags/fr.png new file mode 100644 index 0000000..8332c4e Binary files /dev/null and b/lib/ts3phpframework/images/flags/fr.png differ diff --git a/lib/ts3phpframework/images/flags/ga.png b/lib/ts3phpframework/images/flags/ga.png new file mode 100644 index 0000000..0e0d434 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ga.png differ diff --git a/lib/ts3phpframework/images/flags/gb.png b/lib/ts3phpframework/images/flags/gb.png new file mode 100644 index 0000000..ff701e1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gb.png differ diff --git a/lib/ts3phpframework/images/flags/gd.png b/lib/ts3phpframework/images/flags/gd.png new file mode 100644 index 0000000..9ab57f5 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gd.png differ diff --git a/lib/ts3phpframework/images/flags/ge.png b/lib/ts3phpframework/images/flags/ge.png new file mode 100644 index 0000000..728d970 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ge.png differ diff --git a/lib/ts3phpframework/images/flags/gf.png b/lib/ts3phpframework/images/flags/gf.png new file mode 100644 index 0000000..8332c4e Binary files /dev/null and b/lib/ts3phpframework/images/flags/gf.png differ diff --git a/lib/ts3phpframework/images/flags/gg.png b/lib/ts3phpframework/images/flags/gg.png new file mode 100644 index 0000000..4a916e8 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gg.png differ diff --git a/lib/ts3phpframework/images/flags/gh.png b/lib/ts3phpframework/images/flags/gh.png new file mode 100644 index 0000000..4e2f896 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gh.png differ diff --git a/lib/ts3phpframework/images/flags/gi.png b/lib/ts3phpframework/images/flags/gi.png new file mode 100644 index 0000000..e76797f Binary files /dev/null and b/lib/ts3phpframework/images/flags/gi.png differ diff --git a/lib/ts3phpframework/images/flags/gl.png b/lib/ts3phpframework/images/flags/gl.png new file mode 100644 index 0000000..ef12a73 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gl.png differ diff --git a/lib/ts3phpframework/images/flags/gm.png b/lib/ts3phpframework/images/flags/gm.png new file mode 100644 index 0000000..0720b66 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gm.png differ diff --git a/lib/ts3phpframework/images/flags/gn.png b/lib/ts3phpframework/images/flags/gn.png new file mode 100644 index 0000000..ea660b0 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gn.png differ diff --git a/lib/ts3phpframework/images/flags/gp.png b/lib/ts3phpframework/images/flags/gp.png new file mode 100644 index 0000000..dbb086d Binary files /dev/null and b/lib/ts3phpframework/images/flags/gp.png differ diff --git a/lib/ts3phpframework/images/flags/gq.png b/lib/ts3phpframework/images/flags/gq.png new file mode 100644 index 0000000..ebe20a2 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gq.png differ diff --git a/lib/ts3phpframework/images/flags/gr.png b/lib/ts3phpframework/images/flags/gr.png new file mode 100644 index 0000000..8651ade Binary files /dev/null and b/lib/ts3phpframework/images/flags/gr.png differ diff --git a/lib/ts3phpframework/images/flags/gs.png b/lib/ts3phpframework/images/flags/gs.png new file mode 100644 index 0000000..7ef0bf5 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gs.png differ diff --git a/lib/ts3phpframework/images/flags/gt.png b/lib/ts3phpframework/images/flags/gt.png new file mode 100644 index 0000000..c43a70d Binary files /dev/null and b/lib/ts3phpframework/images/flags/gt.png differ diff --git a/lib/ts3phpframework/images/flags/gu.png b/lib/ts3phpframework/images/flags/gu.png new file mode 100644 index 0000000..92f37c0 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gu.png differ diff --git a/lib/ts3phpframework/images/flags/gw.png b/lib/ts3phpframework/images/flags/gw.png new file mode 100644 index 0000000..b37bcf0 Binary files /dev/null and b/lib/ts3phpframework/images/flags/gw.png differ diff --git a/lib/ts3phpframework/images/flags/gy.png b/lib/ts3phpframework/images/flags/gy.png new file mode 100644 index 0000000..22cbe2f Binary files /dev/null and b/lib/ts3phpframework/images/flags/gy.png differ diff --git a/lib/ts3phpframework/images/flags/hk.png b/lib/ts3phpframework/images/flags/hk.png new file mode 100644 index 0000000..d5c380c Binary files /dev/null and b/lib/ts3phpframework/images/flags/hk.png differ diff --git a/lib/ts3phpframework/images/flags/hm.png b/lib/ts3phpframework/images/flags/hm.png new file mode 100644 index 0000000..a01389a Binary files /dev/null and b/lib/ts3phpframework/images/flags/hm.png differ diff --git a/lib/ts3phpframework/images/flags/hn.png b/lib/ts3phpframework/images/flags/hn.png new file mode 100644 index 0000000..96f8388 Binary files /dev/null and b/lib/ts3phpframework/images/flags/hn.png differ diff --git a/lib/ts3phpframework/images/flags/hr.png b/lib/ts3phpframework/images/flags/hr.png new file mode 100644 index 0000000..696b515 Binary files /dev/null and b/lib/ts3phpframework/images/flags/hr.png differ diff --git a/lib/ts3phpframework/images/flags/ht.png b/lib/ts3phpframework/images/flags/ht.png new file mode 100644 index 0000000..416052a Binary files /dev/null and b/lib/ts3phpframework/images/flags/ht.png differ diff --git a/lib/ts3phpframework/images/flags/hu.png b/lib/ts3phpframework/images/flags/hu.png new file mode 100644 index 0000000..7baafe4 Binary files /dev/null and b/lib/ts3phpframework/images/flags/hu.png differ diff --git a/lib/ts3phpframework/images/flags/id.png b/lib/ts3phpframework/images/flags/id.png new file mode 100644 index 0000000..c6bc0fa Binary files /dev/null and b/lib/ts3phpframework/images/flags/id.png differ diff --git a/lib/ts3phpframework/images/flags/ie.png b/lib/ts3phpframework/images/flags/ie.png new file mode 100644 index 0000000..26baa31 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ie.png differ diff --git a/lib/ts3phpframework/images/flags/il.png b/lib/ts3phpframework/images/flags/il.png new file mode 100644 index 0000000..2ca772d Binary files /dev/null and b/lib/ts3phpframework/images/flags/il.png differ diff --git a/lib/ts3phpframework/images/flags/im.png b/lib/ts3phpframework/images/flags/im.png new file mode 100644 index 0000000..7c028b6 Binary files /dev/null and b/lib/ts3phpframework/images/flags/im.png differ diff --git a/lib/ts3phpframework/images/flags/in.png b/lib/ts3phpframework/images/flags/in.png new file mode 100644 index 0000000..e4d7e81 Binary files /dev/null and b/lib/ts3phpframework/images/flags/in.png differ diff --git a/lib/ts3phpframework/images/flags/io.png b/lib/ts3phpframework/images/flags/io.png new file mode 100644 index 0000000..3e74b6a Binary files /dev/null and b/lib/ts3phpframework/images/flags/io.png differ diff --git a/lib/ts3phpframework/images/flags/iq.png b/lib/ts3phpframework/images/flags/iq.png new file mode 100644 index 0000000..878a351 Binary files /dev/null and b/lib/ts3phpframework/images/flags/iq.png differ diff --git a/lib/ts3phpframework/images/flags/ir.png b/lib/ts3phpframework/images/flags/ir.png new file mode 100644 index 0000000..c5fd136 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ir.png differ diff --git a/lib/ts3phpframework/images/flags/is.png b/lib/ts3phpframework/images/flags/is.png new file mode 100644 index 0000000..b8f6d0f Binary files /dev/null and b/lib/ts3phpframework/images/flags/is.png differ diff --git a/lib/ts3phpframework/images/flags/it.png b/lib/ts3phpframework/images/flags/it.png new file mode 100644 index 0000000..89692f7 Binary files /dev/null and b/lib/ts3phpframework/images/flags/it.png differ diff --git a/lib/ts3phpframework/images/flags/je.png b/lib/ts3phpframework/images/flags/je.png new file mode 100644 index 0000000..5849880 Binary files /dev/null and b/lib/ts3phpframework/images/flags/je.png differ diff --git a/lib/ts3phpframework/images/flags/jm.png b/lib/ts3phpframework/images/flags/jm.png new file mode 100644 index 0000000..7be119e Binary files /dev/null and b/lib/ts3phpframework/images/flags/jm.png differ diff --git a/lib/ts3phpframework/images/flags/jo.png b/lib/ts3phpframework/images/flags/jo.png new file mode 100644 index 0000000..11bd497 Binary files /dev/null and b/lib/ts3phpframework/images/flags/jo.png differ diff --git a/lib/ts3phpframework/images/flags/jp.png b/lib/ts3phpframework/images/flags/jp.png new file mode 100644 index 0000000..325fbad Binary files /dev/null and b/lib/ts3phpframework/images/flags/jp.png differ diff --git a/lib/ts3phpframework/images/flags/ke.png b/lib/ts3phpframework/images/flags/ke.png new file mode 100644 index 0000000..51879ad Binary files /dev/null and b/lib/ts3phpframework/images/flags/ke.png differ diff --git a/lib/ts3phpframework/images/flags/kg.png b/lib/ts3phpframework/images/flags/kg.png new file mode 100644 index 0000000..0a818f6 Binary files /dev/null and b/lib/ts3phpframework/images/flags/kg.png differ diff --git a/lib/ts3phpframework/images/flags/kh.png b/lib/ts3phpframework/images/flags/kh.png new file mode 100644 index 0000000..30f6bb1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/kh.png differ diff --git a/lib/ts3phpframework/images/flags/ki.png b/lib/ts3phpframework/images/flags/ki.png new file mode 100644 index 0000000..2dcce4b Binary files /dev/null and b/lib/ts3phpframework/images/flags/ki.png differ diff --git a/lib/ts3phpframework/images/flags/km.png b/lib/ts3phpframework/images/flags/km.png new file mode 100644 index 0000000..812b2f5 Binary files /dev/null and b/lib/ts3phpframework/images/flags/km.png differ diff --git a/lib/ts3phpframework/images/flags/kn.png b/lib/ts3phpframework/images/flags/kn.png new file mode 100644 index 0000000..febd5b4 Binary files /dev/null and b/lib/ts3phpframework/images/flags/kn.png differ diff --git a/lib/ts3phpframework/images/flags/kp.png b/lib/ts3phpframework/images/flags/kp.png new file mode 100644 index 0000000..d3d509a Binary files /dev/null and b/lib/ts3phpframework/images/flags/kp.png differ diff --git a/lib/ts3phpframework/images/flags/kr.png b/lib/ts3phpframework/images/flags/kr.png new file mode 100644 index 0000000..9c0a78e Binary files /dev/null and b/lib/ts3phpframework/images/flags/kr.png differ diff --git a/lib/ts3phpframework/images/flags/kw.png b/lib/ts3phpframework/images/flags/kw.png new file mode 100644 index 0000000..96546da Binary files /dev/null and b/lib/ts3phpframework/images/flags/kw.png differ diff --git a/lib/ts3phpframework/images/flags/ky.png b/lib/ts3phpframework/images/flags/ky.png new file mode 100644 index 0000000..15c5f8e Binary files /dev/null and b/lib/ts3phpframework/images/flags/ky.png differ diff --git a/lib/ts3phpframework/images/flags/kz.png b/lib/ts3phpframework/images/flags/kz.png new file mode 100644 index 0000000..45a8c88 Binary files /dev/null and b/lib/ts3phpframework/images/flags/kz.png differ diff --git a/lib/ts3phpframework/images/flags/la.png b/lib/ts3phpframework/images/flags/la.png new file mode 100644 index 0000000..e28acd0 Binary files /dev/null and b/lib/ts3phpframework/images/flags/la.png differ diff --git a/lib/ts3phpframework/images/flags/lb.png b/lib/ts3phpframework/images/flags/lb.png new file mode 100644 index 0000000..d0d452b Binary files /dev/null and b/lib/ts3phpframework/images/flags/lb.png differ diff --git a/lib/ts3phpframework/images/flags/lc.png b/lib/ts3phpframework/images/flags/lc.png new file mode 100644 index 0000000..a47d065 Binary files /dev/null and b/lib/ts3phpframework/images/flags/lc.png differ diff --git a/lib/ts3phpframework/images/flags/li.png b/lib/ts3phpframework/images/flags/li.png new file mode 100644 index 0000000..6469909 Binary files /dev/null and b/lib/ts3phpframework/images/flags/li.png differ diff --git a/lib/ts3phpframework/images/flags/lk.png b/lib/ts3phpframework/images/flags/lk.png new file mode 100644 index 0000000..088aad6 Binary files /dev/null and b/lib/ts3phpframework/images/flags/lk.png differ diff --git a/lib/ts3phpframework/images/flags/lr.png b/lib/ts3phpframework/images/flags/lr.png new file mode 100644 index 0000000..89a5bc7 Binary files /dev/null and b/lib/ts3phpframework/images/flags/lr.png differ diff --git a/lib/ts3phpframework/images/flags/ls.png b/lib/ts3phpframework/images/flags/ls.png new file mode 100644 index 0000000..33fdef1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ls.png differ diff --git a/lib/ts3phpframework/images/flags/lt.png b/lib/ts3phpframework/images/flags/lt.png new file mode 100644 index 0000000..c8ef0da Binary files /dev/null and b/lib/ts3phpframework/images/flags/lt.png differ diff --git a/lib/ts3phpframework/images/flags/lu.png b/lib/ts3phpframework/images/flags/lu.png new file mode 100644 index 0000000..4cabba9 Binary files /dev/null and b/lib/ts3phpframework/images/flags/lu.png differ diff --git a/lib/ts3phpframework/images/flags/lv.png b/lib/ts3phpframework/images/flags/lv.png new file mode 100644 index 0000000..49b6998 Binary files /dev/null and b/lib/ts3phpframework/images/flags/lv.png differ diff --git a/lib/ts3phpframework/images/flags/ly.png b/lib/ts3phpframework/images/flags/ly.png new file mode 100644 index 0000000..ff3e2f1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ly.png differ diff --git a/lib/ts3phpframework/images/flags/ma.png b/lib/ts3phpframework/images/flags/ma.png new file mode 100644 index 0000000..f386770 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ma.png differ diff --git a/lib/ts3phpframework/images/flags/mc.png b/lib/ts3phpframework/images/flags/mc.png new file mode 100644 index 0000000..1aa830f Binary files /dev/null and b/lib/ts3phpframework/images/flags/mc.png differ diff --git a/lib/ts3phpframework/images/flags/md.png b/lib/ts3phpframework/images/flags/md.png new file mode 100644 index 0000000..4e92c18 Binary files /dev/null and b/lib/ts3phpframework/images/flags/md.png differ diff --git a/lib/ts3phpframework/images/flags/me.png b/lib/ts3phpframework/images/flags/me.png new file mode 100644 index 0000000..ac72535 Binary files /dev/null and b/lib/ts3phpframework/images/flags/me.png differ diff --git a/lib/ts3phpframework/images/flags/mg.png b/lib/ts3phpframework/images/flags/mg.png new file mode 100644 index 0000000..d2715b3 Binary files /dev/null and b/lib/ts3phpframework/images/flags/mg.png differ diff --git a/lib/ts3phpframework/images/flags/mh.png b/lib/ts3phpframework/images/flags/mh.png new file mode 100644 index 0000000..fb523a8 Binary files /dev/null and b/lib/ts3phpframework/images/flags/mh.png differ diff --git a/lib/ts3phpframework/images/flags/mk.png b/lib/ts3phpframework/images/flags/mk.png new file mode 100644 index 0000000..db173aa Binary files /dev/null and b/lib/ts3phpframework/images/flags/mk.png differ diff --git a/lib/ts3phpframework/images/flags/ml.png b/lib/ts3phpframework/images/flags/ml.png new file mode 100644 index 0000000..2cec8ba Binary files /dev/null and b/lib/ts3phpframework/images/flags/ml.png differ diff --git a/lib/ts3phpframework/images/flags/mm.png b/lib/ts3phpframework/images/flags/mm.png new file mode 100644 index 0000000..f464f67 Binary files /dev/null and b/lib/ts3phpframework/images/flags/mm.png differ diff --git a/lib/ts3phpframework/images/flags/mn.png b/lib/ts3phpframework/images/flags/mn.png new file mode 100644 index 0000000..9396355 Binary files /dev/null and b/lib/ts3phpframework/images/flags/mn.png differ diff --git a/lib/ts3phpframework/images/flags/mo.png b/lib/ts3phpframework/images/flags/mo.png new file mode 100644 index 0000000..deb801d Binary files /dev/null and b/lib/ts3phpframework/images/flags/mo.png differ diff --git a/lib/ts3phpframework/images/flags/mp.png b/lib/ts3phpframework/images/flags/mp.png new file mode 100644 index 0000000..298d588 Binary files /dev/null and b/lib/ts3phpframework/images/flags/mp.png differ diff --git a/lib/ts3phpframework/images/flags/mq.png b/lib/ts3phpframework/images/flags/mq.png new file mode 100644 index 0000000..010143b Binary files /dev/null and b/lib/ts3phpframework/images/flags/mq.png differ diff --git a/lib/ts3phpframework/images/flags/mr.png b/lib/ts3phpframework/images/flags/mr.png new file mode 100644 index 0000000..319546b Binary files /dev/null and b/lib/ts3phpframework/images/flags/mr.png differ diff --git a/lib/ts3phpframework/images/flags/ms.png b/lib/ts3phpframework/images/flags/ms.png new file mode 100644 index 0000000..d4cbb43 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ms.png differ diff --git a/lib/ts3phpframework/images/flags/mt.png b/lib/ts3phpframework/images/flags/mt.png new file mode 100644 index 0000000..00af948 Binary files /dev/null and b/lib/ts3phpframework/images/flags/mt.png differ diff --git a/lib/ts3phpframework/images/flags/mu.png b/lib/ts3phpframework/images/flags/mu.png new file mode 100644 index 0000000..b7fdce1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/mu.png differ diff --git a/lib/ts3phpframework/images/flags/mv.png b/lib/ts3phpframework/images/flags/mv.png new file mode 100644 index 0000000..5073d9e Binary files /dev/null and b/lib/ts3phpframework/images/flags/mv.png differ diff --git a/lib/ts3phpframework/images/flags/mw.png b/lib/ts3phpframework/images/flags/mw.png new file mode 100644 index 0000000..13886e9 Binary files /dev/null and b/lib/ts3phpframework/images/flags/mw.png differ diff --git a/lib/ts3phpframework/images/flags/mx.png b/lib/ts3phpframework/images/flags/mx.png new file mode 100644 index 0000000..5bc58ab Binary files /dev/null and b/lib/ts3phpframework/images/flags/mx.png differ diff --git a/lib/ts3phpframework/images/flags/my.png b/lib/ts3phpframework/images/flags/my.png new file mode 100644 index 0000000..9034cba Binary files /dev/null and b/lib/ts3phpframework/images/flags/my.png differ diff --git a/lib/ts3phpframework/images/flags/mz.png b/lib/ts3phpframework/images/flags/mz.png new file mode 100644 index 0000000..76405e0 Binary files /dev/null and b/lib/ts3phpframework/images/flags/mz.png differ diff --git a/lib/ts3phpframework/images/flags/na.png b/lib/ts3phpframework/images/flags/na.png new file mode 100644 index 0000000..63358c6 Binary files /dev/null and b/lib/ts3phpframework/images/flags/na.png differ diff --git a/lib/ts3phpframework/images/flags/nc.png b/lib/ts3phpframework/images/flags/nc.png new file mode 100644 index 0000000..2cad283 Binary files /dev/null and b/lib/ts3phpframework/images/flags/nc.png differ diff --git a/lib/ts3phpframework/images/flags/ne.png b/lib/ts3phpframework/images/flags/ne.png new file mode 100644 index 0000000..d85f424 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ne.png differ diff --git a/lib/ts3phpframework/images/flags/nf.png b/lib/ts3phpframework/images/flags/nf.png new file mode 100644 index 0000000..f9bcdda Binary files /dev/null and b/lib/ts3phpframework/images/flags/nf.png differ diff --git a/lib/ts3phpframework/images/flags/ng.png b/lib/ts3phpframework/images/flags/ng.png new file mode 100644 index 0000000..3eea2e0 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ng.png differ diff --git a/lib/ts3phpframework/images/flags/ni.png b/lib/ts3phpframework/images/flags/ni.png new file mode 100644 index 0000000..3969aaa Binary files /dev/null and b/lib/ts3phpframework/images/flags/ni.png differ diff --git a/lib/ts3phpframework/images/flags/nl.png b/lib/ts3phpframework/images/flags/nl.png new file mode 100644 index 0000000..fe44791 Binary files /dev/null and b/lib/ts3phpframework/images/flags/nl.png differ diff --git a/lib/ts3phpframework/images/flags/no.png b/lib/ts3phpframework/images/flags/no.png new file mode 100644 index 0000000..160b6b5 Binary files /dev/null and b/lib/ts3phpframework/images/flags/no.png differ diff --git a/lib/ts3phpframework/images/flags/np.png b/lib/ts3phpframework/images/flags/np.png new file mode 100644 index 0000000..aeb058b Binary files /dev/null and b/lib/ts3phpframework/images/flags/np.png differ diff --git a/lib/ts3phpframework/images/flags/nr.png b/lib/ts3phpframework/images/flags/nr.png new file mode 100644 index 0000000..705fc33 Binary files /dev/null and b/lib/ts3phpframework/images/flags/nr.png differ diff --git a/lib/ts3phpframework/images/flags/nu.png b/lib/ts3phpframework/images/flags/nu.png new file mode 100644 index 0000000..c3ce4ae Binary files /dev/null and b/lib/ts3phpframework/images/flags/nu.png differ diff --git a/lib/ts3phpframework/images/flags/nz.png b/lib/ts3phpframework/images/flags/nz.png new file mode 100644 index 0000000..10d6306 Binary files /dev/null and b/lib/ts3phpframework/images/flags/nz.png differ diff --git a/lib/ts3phpframework/images/flags/om.png b/lib/ts3phpframework/images/flags/om.png new file mode 100644 index 0000000..2ffba7e Binary files /dev/null and b/lib/ts3phpframework/images/flags/om.png differ diff --git a/lib/ts3phpframework/images/flags/pa.png b/lib/ts3phpframework/images/flags/pa.png new file mode 100644 index 0000000..9b2ee9a Binary files /dev/null and b/lib/ts3phpframework/images/flags/pa.png differ diff --git a/lib/ts3phpframework/images/flags/pe.png b/lib/ts3phpframework/images/flags/pe.png new file mode 100644 index 0000000..62a0497 Binary files /dev/null and b/lib/ts3phpframework/images/flags/pe.png differ diff --git a/lib/ts3phpframework/images/flags/pf.png b/lib/ts3phpframework/images/flags/pf.png new file mode 100644 index 0000000..771a0f6 Binary files /dev/null and b/lib/ts3phpframework/images/flags/pf.png differ diff --git a/lib/ts3phpframework/images/flags/pg.png b/lib/ts3phpframework/images/flags/pg.png new file mode 100644 index 0000000..10d6233 Binary files /dev/null and b/lib/ts3phpframework/images/flags/pg.png differ diff --git a/lib/ts3phpframework/images/flags/ph.png b/lib/ts3phpframework/images/flags/ph.png new file mode 100644 index 0000000..b89e159 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ph.png differ diff --git a/lib/ts3phpframework/images/flags/pk.png b/lib/ts3phpframework/images/flags/pk.png new file mode 100644 index 0000000..e9df70c Binary files /dev/null and b/lib/ts3phpframework/images/flags/pk.png differ diff --git a/lib/ts3phpframework/images/flags/pl.png b/lib/ts3phpframework/images/flags/pl.png new file mode 100644 index 0000000..d413d01 Binary files /dev/null and b/lib/ts3phpframework/images/flags/pl.png differ diff --git a/lib/ts3phpframework/images/flags/pm.png b/lib/ts3phpframework/images/flags/pm.png new file mode 100644 index 0000000..ba91d2c Binary files /dev/null and b/lib/ts3phpframework/images/flags/pm.png differ diff --git a/lib/ts3phpframework/images/flags/pn.png b/lib/ts3phpframework/images/flags/pn.png new file mode 100644 index 0000000..aa9344f Binary files /dev/null and b/lib/ts3phpframework/images/flags/pn.png differ diff --git a/lib/ts3phpframework/images/flags/pr.png b/lib/ts3phpframework/images/flags/pr.png new file mode 100644 index 0000000..82d9130 Binary files /dev/null and b/lib/ts3phpframework/images/flags/pr.png differ diff --git a/lib/ts3phpframework/images/flags/ps.png b/lib/ts3phpframework/images/flags/ps.png new file mode 100644 index 0000000..f5f5477 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ps.png differ diff --git a/lib/ts3phpframework/images/flags/pt.png b/lib/ts3phpframework/images/flags/pt.png new file mode 100644 index 0000000..ece7980 Binary files /dev/null and b/lib/ts3phpframework/images/flags/pt.png differ diff --git a/lib/ts3phpframework/images/flags/pw.png b/lib/ts3phpframework/images/flags/pw.png new file mode 100644 index 0000000..6178b25 Binary files /dev/null and b/lib/ts3phpframework/images/flags/pw.png differ diff --git a/lib/ts3phpframework/images/flags/py.png b/lib/ts3phpframework/images/flags/py.png new file mode 100644 index 0000000..cb8723c Binary files /dev/null and b/lib/ts3phpframework/images/flags/py.png differ diff --git a/lib/ts3phpframework/images/flags/qa.png b/lib/ts3phpframework/images/flags/qa.png new file mode 100644 index 0000000..ed4c621 Binary files /dev/null and b/lib/ts3phpframework/images/flags/qa.png differ diff --git a/lib/ts3phpframework/images/flags/re.png b/lib/ts3phpframework/images/flags/re.png new file mode 100644 index 0000000..8332c4e Binary files /dev/null and b/lib/ts3phpframework/images/flags/re.png differ diff --git a/lib/ts3phpframework/images/flags/ro.png b/lib/ts3phpframework/images/flags/ro.png new file mode 100644 index 0000000..57e74a6 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ro.png differ diff --git a/lib/ts3phpframework/images/flags/rs.png b/lib/ts3phpframework/images/flags/rs.png new file mode 100644 index 0000000..9439a5b Binary files /dev/null and b/lib/ts3phpframework/images/flags/rs.png differ diff --git a/lib/ts3phpframework/images/flags/ru.png b/lib/ts3phpframework/images/flags/ru.png new file mode 100644 index 0000000..47da421 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ru.png differ diff --git a/lib/ts3phpframework/images/flags/rw.png b/lib/ts3phpframework/images/flags/rw.png new file mode 100644 index 0000000..5356491 Binary files /dev/null and b/lib/ts3phpframework/images/flags/rw.png differ diff --git a/lib/ts3phpframework/images/flags/sa.png b/lib/ts3phpframework/images/flags/sa.png new file mode 100644 index 0000000..b4641c7 Binary files /dev/null and b/lib/ts3phpframework/images/flags/sa.png differ diff --git a/lib/ts3phpframework/images/flags/sb.png b/lib/ts3phpframework/images/flags/sb.png new file mode 100644 index 0000000..a9937cc Binary files /dev/null and b/lib/ts3phpframework/images/flags/sb.png differ diff --git a/lib/ts3phpframework/images/flags/sc.png b/lib/ts3phpframework/images/flags/sc.png new file mode 100644 index 0000000..39ee371 Binary files /dev/null and b/lib/ts3phpframework/images/flags/sc.png differ diff --git a/lib/ts3phpframework/images/flags/sd.png b/lib/ts3phpframework/images/flags/sd.png new file mode 100644 index 0000000..eaab69e Binary files /dev/null and b/lib/ts3phpframework/images/flags/sd.png differ diff --git a/lib/ts3phpframework/images/flags/se.png b/lib/ts3phpframework/images/flags/se.png new file mode 100644 index 0000000..1994653 Binary files /dev/null and b/lib/ts3phpframework/images/flags/se.png differ diff --git a/lib/ts3phpframework/images/flags/sg.png b/lib/ts3phpframework/images/flags/sg.png new file mode 100644 index 0000000..dd34d61 Binary files /dev/null and b/lib/ts3phpframework/images/flags/sg.png differ diff --git a/lib/ts3phpframework/images/flags/sh.png b/lib/ts3phpframework/images/flags/sh.png new file mode 100644 index 0000000..4b1d2a2 Binary files /dev/null and b/lib/ts3phpframework/images/flags/sh.png differ diff --git a/lib/ts3phpframework/images/flags/si.png b/lib/ts3phpframework/images/flags/si.png new file mode 100644 index 0000000..bb1476f Binary files /dev/null and b/lib/ts3phpframework/images/flags/si.png differ diff --git a/lib/ts3phpframework/images/flags/sj.png b/lib/ts3phpframework/images/flags/sj.png new file mode 100644 index 0000000..160b6b5 Binary files /dev/null and b/lib/ts3phpframework/images/flags/sj.png differ diff --git a/lib/ts3phpframework/images/flags/sk.png b/lib/ts3phpframework/images/flags/sk.png new file mode 100644 index 0000000..7ccbc82 Binary files /dev/null and b/lib/ts3phpframework/images/flags/sk.png differ diff --git a/lib/ts3phpframework/images/flags/sl.png b/lib/ts3phpframework/images/flags/sl.png new file mode 100644 index 0000000..12d812d Binary files /dev/null and b/lib/ts3phpframework/images/flags/sl.png differ diff --git a/lib/ts3phpframework/images/flags/sm.png b/lib/ts3phpframework/images/flags/sm.png new file mode 100644 index 0000000..3df2fdc Binary files /dev/null and b/lib/ts3phpframework/images/flags/sm.png differ diff --git a/lib/ts3phpframework/images/flags/sn.png b/lib/ts3phpframework/images/flags/sn.png new file mode 100644 index 0000000..eabb71d Binary files /dev/null and b/lib/ts3phpframework/images/flags/sn.png differ diff --git a/lib/ts3phpframework/images/flags/so.png b/lib/ts3phpframework/images/flags/so.png new file mode 100644 index 0000000..4a1ea4b Binary files /dev/null and b/lib/ts3phpframework/images/flags/so.png differ diff --git a/lib/ts3phpframework/images/flags/sr.png b/lib/ts3phpframework/images/flags/sr.png new file mode 100644 index 0000000..5eff927 Binary files /dev/null and b/lib/ts3phpframework/images/flags/sr.png differ diff --git a/lib/ts3phpframework/images/flags/st.png b/lib/ts3phpframework/images/flags/st.png new file mode 100644 index 0000000..2978557 Binary files /dev/null and b/lib/ts3phpframework/images/flags/st.png differ diff --git a/lib/ts3phpframework/images/flags/sv.png b/lib/ts3phpframework/images/flags/sv.png new file mode 100644 index 0000000..2498799 Binary files /dev/null and b/lib/ts3phpframework/images/flags/sv.png differ diff --git a/lib/ts3phpframework/images/flags/sy.png b/lib/ts3phpframework/images/flags/sy.png new file mode 100644 index 0000000..f5ce30d Binary files /dev/null and b/lib/ts3phpframework/images/flags/sy.png differ diff --git a/lib/ts3phpframework/images/flags/sz.png b/lib/ts3phpframework/images/flags/sz.png new file mode 100644 index 0000000..914ee86 Binary files /dev/null and b/lib/ts3phpframework/images/flags/sz.png differ diff --git a/lib/ts3phpframework/images/flags/tc.png b/lib/ts3phpframework/images/flags/tc.png new file mode 100644 index 0000000..8fc1156 Binary files /dev/null and b/lib/ts3phpframework/images/flags/tc.png differ diff --git a/lib/ts3phpframework/images/flags/td.png b/lib/ts3phpframework/images/flags/td.png new file mode 100644 index 0000000..667f21f Binary files /dev/null and b/lib/ts3phpframework/images/flags/td.png differ diff --git a/lib/ts3phpframework/images/flags/tf.png b/lib/ts3phpframework/images/flags/tf.png new file mode 100644 index 0000000..80529a4 Binary files /dev/null and b/lib/ts3phpframework/images/flags/tf.png differ diff --git a/lib/ts3phpframework/images/flags/tg.png b/lib/ts3phpframework/images/flags/tg.png new file mode 100644 index 0000000..3aa00ad Binary files /dev/null and b/lib/ts3phpframework/images/flags/tg.png differ diff --git a/lib/ts3phpframework/images/flags/th.png b/lib/ts3phpframework/images/flags/th.png new file mode 100644 index 0000000..dd8ba91 Binary files /dev/null and b/lib/ts3phpframework/images/flags/th.png differ diff --git a/lib/ts3phpframework/images/flags/tj.png b/lib/ts3phpframework/images/flags/tj.png new file mode 100644 index 0000000..617bf64 Binary files /dev/null and b/lib/ts3phpframework/images/flags/tj.png differ diff --git a/lib/ts3phpframework/images/flags/tk.png b/lib/ts3phpframework/images/flags/tk.png new file mode 100644 index 0000000..67b8c8c Binary files /dev/null and b/lib/ts3phpframework/images/flags/tk.png differ diff --git a/lib/ts3phpframework/images/flags/tl.png b/lib/ts3phpframework/images/flags/tl.png new file mode 100644 index 0000000..77da181 Binary files /dev/null and b/lib/ts3phpframework/images/flags/tl.png differ diff --git a/lib/ts3phpframework/images/flags/tm.png b/lib/ts3phpframework/images/flags/tm.png new file mode 100644 index 0000000..828020e Binary files /dev/null and b/lib/ts3phpframework/images/flags/tm.png differ diff --git a/lib/ts3phpframework/images/flags/tn.png b/lib/ts3phpframework/images/flags/tn.png new file mode 100644 index 0000000..183cdd3 Binary files /dev/null and b/lib/ts3phpframework/images/flags/tn.png differ diff --git a/lib/ts3phpframework/images/flags/to.png b/lib/ts3phpframework/images/flags/to.png new file mode 100644 index 0000000..f89b8ba Binary files /dev/null and b/lib/ts3phpframework/images/flags/to.png differ diff --git a/lib/ts3phpframework/images/flags/tr.png b/lib/ts3phpframework/images/flags/tr.png new file mode 100644 index 0000000..be32f77 Binary files /dev/null and b/lib/ts3phpframework/images/flags/tr.png differ diff --git a/lib/ts3phpframework/images/flags/tt.png b/lib/ts3phpframework/images/flags/tt.png new file mode 100644 index 0000000..2a11c1e Binary files /dev/null and b/lib/ts3phpframework/images/flags/tt.png differ diff --git a/lib/ts3phpframework/images/flags/tv.png b/lib/ts3phpframework/images/flags/tv.png new file mode 100644 index 0000000..28274c5 Binary files /dev/null and b/lib/ts3phpframework/images/flags/tv.png differ diff --git a/lib/ts3phpframework/images/flags/tw.png b/lib/ts3phpframework/images/flags/tw.png new file mode 100644 index 0000000..f31c654 Binary files /dev/null and b/lib/ts3phpframework/images/flags/tw.png differ diff --git a/lib/ts3phpframework/images/flags/tz.png b/lib/ts3phpframework/images/flags/tz.png new file mode 100644 index 0000000..c00ff79 Binary files /dev/null and b/lib/ts3phpframework/images/flags/tz.png differ diff --git a/lib/ts3phpframework/images/flags/ua.png b/lib/ts3phpframework/images/flags/ua.png new file mode 100644 index 0000000..09563a2 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ua.png differ diff --git a/lib/ts3phpframework/images/flags/ug.png b/lib/ts3phpframework/images/flags/ug.png new file mode 100644 index 0000000..33f4aff Binary files /dev/null and b/lib/ts3phpframework/images/flags/ug.png differ diff --git a/lib/ts3phpframework/images/flags/uk.png b/lib/ts3phpframework/images/flags/uk.png new file mode 100644 index 0000000..ff701e1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/uk.png differ diff --git a/lib/ts3phpframework/images/flags/um.png b/lib/ts3phpframework/images/flags/um.png new file mode 100644 index 0000000..c1dd965 Binary files /dev/null and b/lib/ts3phpframework/images/flags/um.png differ diff --git a/lib/ts3phpframework/images/flags/us.png b/lib/ts3phpframework/images/flags/us.png new file mode 100644 index 0000000..10f451f Binary files /dev/null and b/lib/ts3phpframework/images/flags/us.png differ diff --git a/lib/ts3phpframework/images/flags/uy.png b/lib/ts3phpframework/images/flags/uy.png new file mode 100644 index 0000000..31d948a Binary files /dev/null and b/lib/ts3phpframework/images/flags/uy.png differ diff --git a/lib/ts3phpframework/images/flags/uz.png b/lib/ts3phpframework/images/flags/uz.png new file mode 100644 index 0000000..fef5dc1 Binary files /dev/null and b/lib/ts3phpframework/images/flags/uz.png differ diff --git a/lib/ts3phpframework/images/flags/va.png b/lib/ts3phpframework/images/flags/va.png new file mode 100644 index 0000000..b31eaf2 Binary files /dev/null and b/lib/ts3phpframework/images/flags/va.png differ diff --git a/lib/ts3phpframework/images/flags/vc.png b/lib/ts3phpframework/images/flags/vc.png new file mode 100644 index 0000000..8fa17b0 Binary files /dev/null and b/lib/ts3phpframework/images/flags/vc.png differ diff --git a/lib/ts3phpframework/images/flags/ve.png b/lib/ts3phpframework/images/flags/ve.png new file mode 100644 index 0000000..00c90f9 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ve.png differ diff --git a/lib/ts3phpframework/images/flags/vg.png b/lib/ts3phpframework/images/flags/vg.png new file mode 100644 index 0000000..4156907 Binary files /dev/null and b/lib/ts3phpframework/images/flags/vg.png differ diff --git a/lib/ts3phpframework/images/flags/vi.png b/lib/ts3phpframework/images/flags/vi.png new file mode 100644 index 0000000..ed26915 Binary files /dev/null and b/lib/ts3phpframework/images/flags/vi.png differ diff --git a/lib/ts3phpframework/images/flags/vn.png b/lib/ts3phpframework/images/flags/vn.png new file mode 100644 index 0000000..ec7cd48 Binary files /dev/null and b/lib/ts3phpframework/images/flags/vn.png differ diff --git a/lib/ts3phpframework/images/flags/vu.png b/lib/ts3phpframework/images/flags/vu.png new file mode 100644 index 0000000..b3397bc Binary files /dev/null and b/lib/ts3phpframework/images/flags/vu.png differ diff --git a/lib/ts3phpframework/images/flags/wf.png b/lib/ts3phpframework/images/flags/wf.png new file mode 100644 index 0000000..9f95587 Binary files /dev/null and b/lib/ts3phpframework/images/flags/wf.png differ diff --git a/lib/ts3phpframework/images/flags/ws.png b/lib/ts3phpframework/images/flags/ws.png new file mode 100644 index 0000000..c169508 Binary files /dev/null and b/lib/ts3phpframework/images/flags/ws.png differ diff --git a/lib/ts3phpframework/images/flags/ye.png b/lib/ts3phpframework/images/flags/ye.png new file mode 100644 index 0000000..468dfad Binary files /dev/null and b/lib/ts3phpframework/images/flags/ye.png differ diff --git a/lib/ts3phpframework/images/flags/yt.png b/lib/ts3phpframework/images/flags/yt.png new file mode 100644 index 0000000..c298f37 Binary files /dev/null and b/lib/ts3phpframework/images/flags/yt.png differ diff --git a/lib/ts3phpframework/images/flags/za.png b/lib/ts3phpframework/images/flags/za.png new file mode 100644 index 0000000..57c58e2 Binary files /dev/null and b/lib/ts3phpframework/images/flags/za.png differ diff --git a/lib/ts3phpframework/images/flags/zm.png b/lib/ts3phpframework/images/flags/zm.png new file mode 100644 index 0000000..c25b07b Binary files /dev/null and b/lib/ts3phpframework/images/flags/zm.png differ diff --git a/lib/ts3phpframework/images/flags/zw.png b/lib/ts3phpframework/images/flags/zw.png new file mode 100644 index 0000000..53c9725 Binary files /dev/null and b/lib/ts3phpframework/images/flags/zw.png differ diff --git a/lib/ts3phpframework/images/icons/ts3client.ico b/lib/ts3phpframework/images/icons/ts3client.ico new file mode 100644 index 0000000..3b3aef0 Binary files /dev/null and b/lib/ts3phpframework/images/icons/ts3client.ico differ diff --git a/lib/ts3phpframework/images/icons/ts3server.ico b/lib/ts3phpframework/images/icons/ts3server.ico new file mode 100644 index 0000000..3d5c277 Binary files /dev/null and b/lib/ts3phpframework/images/icons/ts3server.ico differ diff --git a/lib/ts3phpframework/images/viewer/channel_flag_default.png b/lib/ts3phpframework/images/viewer/channel_flag_default.png new file mode 100644 index 0000000..4f90c9e Binary files /dev/null and b/lib/ts3phpframework/images/viewer/channel_flag_default.png differ diff --git a/lib/ts3phpframework/images/viewer/channel_flag_moderated.png b/lib/ts3phpframework/images/viewer/channel_flag_moderated.png new file mode 100644 index 0000000..8567a07 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/channel_flag_moderated.png differ diff --git a/lib/ts3phpframework/images/viewer/channel_flag_music.png b/lib/ts3phpframework/images/viewer/channel_flag_music.png new file mode 100644 index 0000000..79f46b0 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/channel_flag_music.png differ diff --git a/lib/ts3phpframework/images/viewer/channel_flag_password.png b/lib/ts3phpframework/images/viewer/channel_flag_password.png new file mode 100644 index 0000000..b4f0770 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/channel_flag_password.png differ diff --git a/lib/ts3phpframework/images/viewer/channel_full.png b/lib/ts3phpframework/images/viewer/channel_full.png new file mode 100644 index 0000000..d7ec28e Binary files /dev/null and b/lib/ts3phpframework/images/viewer/channel_full.png differ diff --git a/lib/ts3phpframework/images/viewer/channel_open.png b/lib/ts3phpframework/images/viewer/channel_open.png new file mode 100644 index 0000000..bed4b52 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/channel_open.png differ diff --git a/lib/ts3phpframework/images/viewer/channel_pass.png b/lib/ts3phpframework/images/viewer/channel_pass.png new file mode 100644 index 0000000..911cf4a Binary files /dev/null and b/lib/ts3phpframework/images/viewer/channel_pass.png differ diff --git a/lib/ts3phpframework/images/viewer/client_away.png b/lib/ts3phpframework/images/viewer/client_away.png new file mode 100644 index 0000000..e5b0cff Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_away.png differ diff --git a/lib/ts3phpframework/images/viewer/client_cc.png b/lib/ts3phpframework/images/viewer/client_cc.png new file mode 100644 index 0000000..8cab896 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_cc.png differ diff --git a/lib/ts3phpframework/images/viewer/client_cc_idle.png b/lib/ts3phpframework/images/viewer/client_cc_idle.png new file mode 100644 index 0000000..ea2b327 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_cc_idle.png differ diff --git a/lib/ts3phpframework/images/viewer/client_cc_talk.png b/lib/ts3phpframework/images/viewer/client_cc_talk.png new file mode 100644 index 0000000..a5f7f8e Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_cc_talk.png differ diff --git a/lib/ts3phpframework/images/viewer/client_idle.png b/lib/ts3phpframework/images/viewer/client_idle.png new file mode 100644 index 0000000..e59cb34 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_idle.png differ diff --git a/lib/ts3phpframework/images/viewer/client_mic_disabled.png b/lib/ts3phpframework/images/viewer/client_mic_disabled.png new file mode 100644 index 0000000..107b725 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_mic_disabled.png differ diff --git a/lib/ts3phpframework/images/viewer/client_mic_muted.png b/lib/ts3phpframework/images/viewer/client_mic_muted.png new file mode 100644 index 0000000..0f632d2 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_mic_muted.png differ diff --git a/lib/ts3phpframework/images/viewer/client_priority.png b/lib/ts3phpframework/images/viewer/client_priority.png new file mode 100644 index 0000000..b54b7b0 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_priority.png differ diff --git a/lib/ts3phpframework/images/viewer/client_query.png b/lib/ts3phpframework/images/viewer/client_query.png new file mode 100644 index 0000000..68f10f1 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_query.png differ diff --git a/lib/ts3phpframework/images/viewer/client_snd_disabled.png b/lib/ts3phpframework/images/viewer/client_snd_disabled.png new file mode 100644 index 0000000..d516d26 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_snd_disabled.png differ diff --git a/lib/ts3phpframework/images/viewer/client_snd_muted.png b/lib/ts3phpframework/images/viewer/client_snd_muted.png new file mode 100644 index 0000000..ad0c302 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_snd_muted.png differ diff --git a/lib/ts3phpframework/images/viewer/client_talk.png b/lib/ts3phpframework/images/viewer/client_talk.png new file mode 100644 index 0000000..42c2c59 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_talk.png differ diff --git a/lib/ts3phpframework/images/viewer/client_talker.png b/lib/ts3phpframework/images/viewer/client_talker.png new file mode 100644 index 0000000..2fcf485 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_talker.png differ diff --git a/lib/ts3phpframework/images/viewer/client_talker_request.png b/lib/ts3phpframework/images/viewer/client_talker_request.png new file mode 100644 index 0000000..5c09ada Binary files /dev/null and b/lib/ts3phpframework/images/viewer/client_talker_request.png differ diff --git a/lib/ts3phpframework/images/viewer/group_channel.png b/lib/ts3phpframework/images/viewer/group_channel.png new file mode 100644 index 0000000..6696f07 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/group_channel.png differ diff --git a/lib/ts3phpframework/images/viewer/group_icon_0.png b/lib/ts3phpframework/images/viewer/group_icon_0.png new file mode 100644 index 0000000..b7f231e Binary files /dev/null and b/lib/ts3phpframework/images/viewer/group_icon_0.png differ diff --git a/lib/ts3phpframework/images/viewer/group_icon_100.png b/lib/ts3phpframework/images/viewer/group_icon_100.png new file mode 100644 index 0000000..7c948d4 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/group_icon_100.png differ diff --git a/lib/ts3phpframework/images/viewer/group_icon_200.png b/lib/ts3phpframework/images/viewer/group_icon_200.png new file mode 100644 index 0000000..4acadb5 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/group_icon_200.png differ diff --git a/lib/ts3phpframework/images/viewer/group_icon_300.png b/lib/ts3phpframework/images/viewer/group_icon_300.png new file mode 100644 index 0000000..d048e3e Binary files /dev/null and b/lib/ts3phpframework/images/viewer/group_icon_300.png differ diff --git a/lib/ts3phpframework/images/viewer/group_icon_400.png b/lib/ts3phpframework/images/viewer/group_icon_400.png new file mode 100644 index 0000000..8a44f0e Binary files /dev/null and b/lib/ts3phpframework/images/viewer/group_icon_400.png differ diff --git a/lib/ts3phpframework/images/viewer/group_icon_500.png b/lib/ts3phpframework/images/viewer/group_icon_500.png new file mode 100644 index 0000000..f303433 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/group_icon_500.png differ diff --git a/lib/ts3phpframework/images/viewer/group_icon_600.png b/lib/ts3phpframework/images/viewer/group_icon_600.png new file mode 100644 index 0000000..d625f2a Binary files /dev/null and b/lib/ts3phpframework/images/viewer/group_icon_600.png differ diff --git a/lib/ts3phpframework/images/viewer/group_server.png b/lib/ts3phpframework/images/viewer/group_server.png new file mode 100644 index 0000000..ee155d6 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/group_server.png differ diff --git a/lib/ts3phpframework/images/viewer/host.png b/lib/ts3phpframework/images/viewer/host.png new file mode 100644 index 0000000..45e43b8 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/host.png differ diff --git a/lib/ts3phpframework/images/viewer/server_full.png b/lib/ts3phpframework/images/viewer/server_full.png new file mode 100644 index 0000000..bfec600 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/server_full.png differ diff --git a/lib/ts3phpframework/images/viewer/server_open.png b/lib/ts3phpframework/images/viewer/server_open.png new file mode 100644 index 0000000..75decbd Binary files /dev/null and b/lib/ts3phpframework/images/viewer/server_open.png differ diff --git a/lib/ts3phpframework/images/viewer/server_pass.png b/lib/ts3phpframework/images/viewer/server_pass.png new file mode 100644 index 0000000..39af1ae Binary files /dev/null and b/lib/ts3phpframework/images/viewer/server_pass.png differ diff --git a/lib/ts3phpframework/images/viewer/spacer_dashdotdotline.gif b/lib/ts3phpframework/images/viewer/spacer_dashdotdotline.gif new file mode 100644 index 0000000..0eb3bb2 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/spacer_dashdotdotline.gif differ diff --git a/lib/ts3phpframework/images/viewer/spacer_dashdotline.gif b/lib/ts3phpframework/images/viewer/spacer_dashdotline.gif new file mode 100644 index 0000000..4dc84ec Binary files /dev/null and b/lib/ts3phpframework/images/viewer/spacer_dashdotline.gif differ diff --git a/lib/ts3phpframework/images/viewer/spacer_dashline.gif b/lib/ts3phpframework/images/viewer/spacer_dashline.gif new file mode 100644 index 0000000..52c7d01 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/spacer_dashline.gif differ diff --git a/lib/ts3phpframework/images/viewer/spacer_dotline.gif b/lib/ts3phpframework/images/viewer/spacer_dotline.gif new file mode 100644 index 0000000..a908598 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/spacer_dotline.gif differ diff --git a/lib/ts3phpframework/images/viewer/spacer_solidline.gif b/lib/ts3phpframework/images/viewer/spacer_solidline.gif new file mode 100644 index 0000000..d8aae2b Binary files /dev/null and b/lib/ts3phpframework/images/viewer/spacer_solidline.gif differ diff --git a/lib/ts3phpframework/images/viewer/tree.png b/lib/ts3phpframework/images/viewer/tree.png new file mode 100644 index 0000000..addd40b Binary files /dev/null and b/lib/ts3phpframework/images/viewer/tree.png differ diff --git a/lib/ts3phpframework/images/viewer/tree_blank.png b/lib/ts3phpframework/images/viewer/tree_blank.png new file mode 100644 index 0000000..07ccff7 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/tree_blank.png differ diff --git a/lib/ts3phpframework/images/viewer/tree_end.gif b/lib/ts3phpframework/images/viewer/tree_end.gif new file mode 100644 index 0000000..b89d56e Binary files /dev/null and b/lib/ts3phpframework/images/viewer/tree_end.gif differ diff --git a/lib/ts3phpframework/images/viewer/tree_line.gif b/lib/ts3phpframework/images/viewer/tree_line.gif new file mode 100644 index 0000000..324204a Binary files /dev/null and b/lib/ts3phpframework/images/viewer/tree_line.gif differ diff --git a/lib/ts3phpframework/images/viewer/tree_mid.gif b/lib/ts3phpframework/images/viewer/tree_mid.gif new file mode 100644 index 0000000..2c8de45 Binary files /dev/null and b/lib/ts3phpframework/images/viewer/tree_mid.gif differ diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Abstract.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Abstract.php new file mode 100644 index 0000000..3edb227 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Abstract.php @@ -0,0 +1,160 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Abstract + * @brief Provides low-level methods for concrete adapters to communicate with a TeamSpeak 3 Server. + */ +abstract class TeamSpeak3_Adapter_Abstract +{ + /** + * Stores user-provided options. + * + * @var array + */ + protected $options = null; + + /** + * Stores an TeamSpeak3_Transport_Abstract object. + * + * @var TeamSpeak3_Transport_Abstract + */ + protected $transport = null; + + /** + * The TeamSpeak3_Adapter_Abstract constructor. + * + * @param array $options + * @return TeamSpeak3_Adapter_Abstract + */ + public function __construct(array $options) + { + $this->options = $options; + + if($this->transport === null) + { + $this->syn(); + } + } + + /** + * The TeamSpeak3_Adapter_Abstract destructor. + * + * @return void + */ + abstract public function __destruct(); + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + abstract protected function syn(); + + /** + * Commit pending data. + * + * @return array + */ + public function __sleep() + { + return array("options"); + } + + /** + * Reconnects to the remote server. + * + * @return void + */ + public function __wakeup() + { + $this->syn(); + } + + /** + * Returns the profiler timer used for this connection adapter. + * + * @return TeamSpeak3_Helper_Profiler_Timer + */ + public function getProfiler() + { + return TeamSpeak3_Helper_Profiler::get(spl_object_hash($this)); + } + + /** + * Returns the transport object used for this connection adapter. + * + * @return TeamSpeak3_Transport_Abstract + */ + public function getTransport() + { + return $this->transport; + } + + /** + * Loads the transport object object used for the connection adapter and passes a given set + * of options. + * + * @param array $options + * @param string $transport + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + protected function initTransport($options, $transport = "TeamSpeak3_Transport_TCP") + { + if(!is_array($options)) + { + throw new TeamSpeak3_Adapter_Exception("transport parameters must provided in an array"); + } + + $this->transport = new $transport($options); + } + + /** + * Returns the hostname or IPv4 address the underlying TeamSpeak3_Transport_Abstract object + * is connected to. + * + * @return string + */ + public function getTransportHost() + { + return $this->getTransport()->getConfig("host", "0.0.0.0"); + } + + /** + * Returns the port number of the server the underlying TeamSpeak3_Transport_Abstract object + * is connected to. + * + * @return string + */ + public function getTransportPort() + { + return $this->getTransport()->getConfig("port", "0"); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Blacklist.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Blacklist.php new file mode 100644 index 0000000..c303ae4 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Blacklist.php @@ -0,0 +1,119 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Blacklist + * @brief Provides methods to check if an IP address is currently blacklisted. + */ +class TeamSpeak3_Adapter_Blacklist extends TeamSpeak3_Adapter_Abstract +{ + /** + * The IPv4 address or FQDN of the TeamSpeak Systems update server. + * + * @var string + */ + protected $default_host = "blacklist.teamspeak.com"; + + /** + * The UDP port number of the TeamSpeak Systems update server. + * + * @var integer + */ + protected $default_port = 17385; + + /** + * Stores an array containing the latest build numbers. + * + * @var array + */ + protected $build_numbers = null; + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @return void + */ + public function syn() + { + if(!isset($this->options["host"]) || empty($this->options["host"])) $this->options["host"] = $this->default_host; + if(!isset($this->options["port"]) || empty($this->options["port"])) $this->options["port"] = $this->default_port; + + $this->initTransport($this->options, "TeamSpeak3_Transport_UDP"); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("blacklistConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_Blacklist destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->getTransport()->isConnected()) + { + $this->getTransport()->disconnect(); + } + } + + /** + * Returns TRUE if a specified $host IP address is currently blacklisted. + * + * @param string $host + * @throws TeamSpeak3_Adapter_Blacklist_Exception + * @return boolean + */ + public function isBlacklisted($host) + { + if(ip2long($host) === FALSE) + { + $addr = gethostbyname($host); + + if($addr == $host) + { + throw new TeamSpeak3_Adapter_Blacklist_Exception("unable to resolve IPv4 address (" . $host . ")"); + } + + $host = $addr; + } + + $this->getTransport()->send("ip4:" . $host); + $repl = $this->getTransport()->read(1); + $this->getTransport()->disconnect(); + + if(!count($repl)) + { + return FALSE; + } + + return ($repl->toInt()) ? FALSE : TRUE; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Blacklist/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Blacklist/Exception.php new file mode 100644 index 0000000..a9e52a7 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Blacklist/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Blacklist_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_Blacklist objects. + */ +class TeamSpeak3_Adapter_Blacklist_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Exception.php new file mode 100644 index 0000000..342ef40 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_Abstract objects. + */ +class TeamSpeak3_Adapter_Exception extends TeamSpeak3_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/FileTransfer.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/FileTransfer.php new file mode 100644 index 0000000..0a78b96 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/FileTransfer.php @@ -0,0 +1,190 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_FileTransfer + * @brief Provides low-level methods for file transfer communication with a TeamSpeak 3 Server. + */ +class TeamSpeak3_Adapter_FileTransfer extends TeamSpeak3_Adapter_Abstract +{ + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + public function syn() + { + $this->initTransport($this->options); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_FileTransfer destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->getTransport()->isConnected()) + { + $this->getTransport()->disconnect(); + } + } + + /** + * Sends a valid file transfer key to the server to initialize the file transfer. + * + * @param string $ftkey + * @throws TeamSpeak3_Adapter_FileTransfer_Exception + * @return void + */ + protected function init($ftkey) + { + if(strlen($ftkey) != 32) + { + throw new TeamSpeak3_Adapter_FileTransfer_Exception("invalid file transfer key format"); + } + + $this->getProfiler()->start(); + $this->getTransport()->send($ftkey); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferHandshake", $this); + } + + /** + * Sends the content of a file to the server. + * + * @param string $ftkey + * @param integer $seek + * @param string $data + * @throws TeamSpeak3_Adapter_FileTransfer_Exception + * @return void + */ + public function upload($ftkey, $seek, $data) + { + $this->init($ftkey); + + $size = strlen($data); + $seek = intval($seek); + $pack = 4096; + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferUploadStarted", $ftkey, $seek, $size); + + for(;$seek < $size;) + { + $rest = $size-$seek; + $pack = $rest < $pack ? $rest : $pack; + $buff = substr($data, $seek, $pack); + $seek = $seek+$pack; + + $this->getTransport()->send($buff); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferUploadProgress", $ftkey, $seek, $size); + } + + $this->getProfiler()->stop(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferUploadFinished", $ftkey, $seek, $size); + + if($seek < $size) + { + throw new TeamSpeak3_Adapter_FileTransfer_Exception("incomplete file upload (" . $seek . " of " . $size . " bytes)"); + } + } + + /** + * Returns the content of a downloaded file as a TeamSpeak3_Helper_String object. + * + * @param string $ftkey + * @param integer $size + * @param boolean $passthru + * @throws TeamSpeak3_Adapter_FileTransfer_Exception + * @return TeamSpeak3_Helper_String + */ + public function download($ftkey, $size, $passthru = FALSE) + { + $this->init($ftkey); + + if($passthru) + { + return $this->passthru($size); + } + + $buff = new TeamSpeak3_Helper_String(""); + $size = intval($size); + $pack = 4096; + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferDownloadStarted", $ftkey, count($buff), $size); + + for($seek = 0;$seek < $size;) + { + $rest = $size-$seek; + $pack = $rest < $pack ? $rest : $pack; + $data = $this->getTransport()->read($rest < $pack ? $rest : $pack); + $seek = $seek+$pack; + + $buff->append($data); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferDownloadProgress", $ftkey, count($buff), $size); + } + + $this->getProfiler()->stop(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferDownloadFinished", $ftkey, count($buff), $size); + + if(strlen($buff) != $size) + { + throw new TeamSpeak3_Adapter_FileTransfer_Exception("incomplete file download (" . count($buff) . " of " . $size . " bytes)"); + } + + return $buff; + } + + /** + * Outputs all remaining data on a TeamSpeak 3 file transfer stream using PHP's fpassthru() + * function. + * + * @param integer $size + * @throws TeamSpeak3_Adapter_FileTransfer_Exception + * @return void + */ + protected function passthru($size) + { + $buff_size = fpassthru($this->getTransport()->getStream()); + + if($buff_size != $size) + { + throw new TeamSpeak3_Adapter_FileTransfer_Exception("incomplete file download (" . intval($buff_size) . " of " . $size . " bytes)"); + } + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/FileTransfer/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/FileTransfer/Exception.php new file mode 100644 index 0000000..add2be5 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/FileTransfer/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_FileTransfer_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_FileTransfer objects. + */ +class TeamSpeak3_Adapter_FileTransfer_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery.php new file mode 100644 index 0000000..38f7db8 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery.php @@ -0,0 +1,261 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_ServerQuery + * @brief Provides low-level methods for ServerQuery communication with a TeamSpeak 3 Server. + */ +class TeamSpeak3_Adapter_ServerQuery extends TeamSpeak3_Adapter_Abstract +{ + /** + * Stores a singleton instance of the active TeamSpeak3_Node_Host object. + * + * @var TeamSpeak3_Node_Host + */ + protected $host = null; + + /** + * Stores the timestamp of the last command. + * + * @var integer + */ + protected $timer = null; + + /** + * Number of queries executed on the server. + * + * @var integer + */ + protected $count = 0; + + /** + * Stores an array with unsupported commands. + * + * @var array + */ + protected $block = array("help"); + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + protected function syn() + { + $this->initTransport($this->options); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + if(!$this->getTransport()->readLine()->startsWith(TeamSpeak3::READY)) + { + throw new TeamSpeak3_Adapter_Exception("invalid reply from the server"); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("serverqueryConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_ServerQuery destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->transport->isConnected()) + { + try + { + $this->request("quit"); + } + catch(Exception $e) + { + return; + } + } + } + + /** + * Sends a prepared command to the server and returns the result. + * + * @param string $cmd + * @param boolean $throw + * @throws TeamSpeak3_Adapter_Exception + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function request($cmd, $throw = TRUE) + { + $query = TeamSpeak3_Helper_String::factory($cmd)->section(TeamSpeak3::SEPARATOR_CELL); + + if(strstr($cmd, "\r") || strstr($cmd, "\n")) + { + throw new TeamSpeak3_Adapter_Exception("illegal characters in command '" . $query . "'"); + } + elseif(in_array($query, $this->block)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("command not found", 0x100); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("serverqueryCommandStarted", $cmd); + + $this->getProfiler()->start(); + $this->getTransport()->sendLine($cmd); + $this->timer = time(); + $this->count++; + + $rpl = array(); + + do { + $str = $this->getTransport()->readLine(); + $rpl[] = $str; + } while($str instanceof TeamSpeak3_Helper_String && $str->section(TeamSpeak3::SEPARATOR_CELL) != TeamSpeak3::ERROR); + + $this->getProfiler()->stop(); + + $reply = new TeamSpeak3_Adapter_ServerQuery_Reply($rpl, $cmd, $this->getHost(), $throw); + + TeamSpeak3_Helper_Signal::getInstance()->emit("serverqueryCommandFinished", $cmd, $reply); + + return $reply; + } + + /** + * Waits for the server to send a notification message and returns the result. + * + * @throws TeamSpeak3_Adapter_Exception + * @return TeamSpeak3_Adapter_ServerQuery_Event + */ + public function wait() + { + if($this->getTransport()->getConfig("blocking")) + { + throw new TeamSpeak3_Adapter_Exception("only available in non-blocking mode"); + } + + do { + $evt = $this->getTransport()->readLine(); + } while($evt instanceof TeamSpeak3_Helper_String && !$evt->section(TeamSpeak3::SEPARATOR_CELL)->startsWith(TeamSpeak3::EVENT)); + + return new TeamSpeak3_Adapter_ServerQuery_Event($evt, $this->getHost()); + } + + /** + * Uses given parameters and returns a prepared ServerQuery command. + * + * @param string $cmd + * @param array $params + * @return string + */ + public function prepare($cmd, array $params = array()) + { + $args = array(); + $cells = array(); + + foreach($params as $ident => $value) + { + $ident = is_numeric($ident) ? "" : strtolower($ident) . TeamSpeak3::SEPARATOR_PAIR; + + if(is_array($value)) + { + $value = array_values($value); + + for($i = 0; $i < count($value); $i++) + { + if($value[$i] === null) continue; + elseif($value[$i] === FALSE) $value[$i] = 0x00; + elseif($value[$i] === TRUE) $value[$i] = 0x01; + elseif($value[$i] instanceof TeamSpeak3_Node_Abstract) $value[$i] = $value[$i]->getId(); + + $cells[$i][] = $ident . TeamSpeak3_Helper_String::factory($value[$i])->escape()->toUtf8(); + } + } + else + { + if($value === null) continue; + elseif($value === FALSE) $value = 0x00; + elseif($value === TRUE) $value = 0x01; + elseif($value instanceof TeamSpeak3_Node_Abstract) $value = $value->getId(); + + $args[] = $ident . TeamSpeak3_Helper_String::factory($value)->escape()->toUtf8(); + } + } + + foreach(array_keys($cells) as $ident) $cells[$ident] = implode(TeamSpeak3::SEPARATOR_CELL, $cells[$ident]); + + if(count($args)) $cmd .= " " . implode(TeamSpeak3::SEPARATOR_CELL, $args); + if(count($cells)) $cmd .= " " . implode(TeamSpeak3::SEPARATOR_LIST, $cells); + + return trim($cmd); + } + + /** + * Returns the timestamp of the last command. + * + * @return integer + */ + public function getQueryLastTimestamp() + { + return $this->timer; + } + + /** + * Returns the number of queries executed on the server. + * + * @return integer + */ + public function getQueryCount() + { + return $this->count; + } + + /** + * Returns the total runtime of all queries. + * + * @return mixed + */ + public function getQueryRuntime() + { + return $this->getProfiler()->getRuntime(); + } + + /** + * Returns the TeamSpeak3_Node_Host object of the current connection. + * + * @return TeamSpeak3_Node_Host + */ + public function getHost() + { + if($this->host === null) + { + $this->host = new TeamSpeak3_Node_Host($this); + } + + return $this->host; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery/Event.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery/Event.php new file mode 100644 index 0000000..5c3c8a7 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery/Event.php @@ -0,0 +1,170 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_ServerQuery_Event + * @brief Provides methods to analyze and format a ServerQuery event. + */ +class TeamSpeak3_Adapter_ServerQuery_Event implements ArrayAccess +{ + /** + * Stores the event type. + * + * @var TeamSpeak3_Helper_String + */ + protected $type = null; + + /** + * Stores the event data. + * + * @var array + */ + protected $data = null; + + /** + * Stores the event data as an unparsed string. + * + * @var TeamSpeak3_Helper_String + */ + protected $mesg = null; + + /** + * Creates a new TeamSpeak3_Adapter_ServerQuery_Event object. + * + * @param TeamSpeak3_Helper_String $evt + * @param TeamSpeak3_Node_Host $con + * @throws TeamSpeak3_Adapter_Exception + * @return TeamSpeak3_Adapter_ServerQuery_Event + */ + public function __construct(TeamSpeak3_Helper_String $evt, TeamSpeak3_Node_Host $con = null) + { + if(!$evt->startsWith(TeamSpeak3::EVENT)) + { + throw new TeamSpeak3_Adapter_Exception("invalid notification event format"); + } + + list($type, $data) = $evt->split(TeamSpeak3::SEPARATOR_CELL, 2); + + if(empty($data)) + { + throw new TeamSpeak3_Adapter_Exception("invalid notification event data"); + } + + $fake = new TeamSpeak3_Helper_String(TeamSpeak3::ERROR . TeamSpeak3::SEPARATOR_CELL . "id" . TeamSpeak3::SEPARATOR_PAIR . 0 . TeamSpeak3::SEPARATOR_CELL . "msg" . TeamSpeak3::SEPARATOR_PAIR . "ok"); + $repl = new TeamSpeak3_Adapter_ServerQuery_Reply(array($data, $fake), $type); + + $this->type = $type->substr(strlen(TeamSpeak3::EVENT)); + $this->data = $repl->toList(); + $this->mesg = $data; + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyEvent", $this, $con); + TeamSpeak3_Helper_Signal::getInstance()->emit("notify" . ucfirst($this->type), $this, $con); + } + + /** + * Returns the event type string. + * + * @return TeamSpeak3_Helper_String + */ + public function getType() + { + return $this->type; + } + + /** + * Returns the event data array. + * + * @return array + */ + public function getData() + { + return $this->data; + } + + /** + * Returns the event data as an unparsed string. + * + * @return TeamSpeak3_Helper_String + */ + public function getMessage() + { + return $this->mesg; + } + + /** + * @ignore + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->data) ? TRUE : FALSE; + } + + /** + * @ignore + */ + public function offsetGet($offset) + { + if(!$this->offsetExists($offset)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + return $this->data[$offset]; + } + + /** + * @ignore + */ + public function offsetSet($offset, $value) + { + throw new TeamSpeak3_Node_Exception("event '" . $this->getType() . "' is read only"); + } + + /** + * @ignore + */ + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } + + /** + * @ignore + */ + public function __get($offset) + { + return $this->offsetGet($offset); + } + + /** + * @ignore + */ + public function __set($offset, $value) + { + $this->offsetSet($offset, $value); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery/Exception.php new file mode 100644 index 0000000..01129a3 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_ServerQuery_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_ServerQuery objects. + */ +class TeamSpeak3_Adapter_ServerQuery_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery/Reply.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery/Reply.php new file mode 100644 index 0000000..5bf6532 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/ServerQuery/Reply.php @@ -0,0 +1,346 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_ServerQuery_Reply + * @brief Provides methods to analyze and format a ServerQuery reply. + */ +class TeamSpeak3_Adapter_ServerQuery_Reply +{ + /** + * Stores the command used to get this reply. + * + * @var TeamSpeak3_Helper_String + */ + protected $cmd = null; + + /** + * Stores the servers reply (if available). + * + * @var TeamSpeak3_Helper_String + */ + protected $rpl = null; + + /** + * Stores connected TeamSpeak3_Node_Host object. + * + * @var TeamSpeak3_Node_Host + */ + protected $con = null; + + /** + * Stores an assoc array containing the error info for this reply. + * + * @var array + */ + protected $err = array(); + + /** + * Sotres an array of events that occured before or during this reply. + * + * @var array + */ + protected $evt = array(); + + /** + * Indicates whether exceptions should be thrown or not. + * + * @var boolean + */ + protected $exp = TRUE; + + /** + * Creates a new TeamSpeak3_Adapter_ServerQuery_Reply object. + * + * @param array $rpl + * @param string $cmd + * @param boolean $exp + * @param TeamSpeak3_Node_Host $con + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function __construct(array $rpl, $cmd = null, TeamSpeak3_Node_Host $con = null, $exp = TRUE) + { + $this->cmd = new TeamSpeak3_Helper_String($cmd); + $this->con = $con; + $this->exp = (bool) $exp; + + $this->fetchError(array_pop($rpl)); + $this->fetchReply($rpl); + } + + /** + * Returns the reply as an TeamSpeak3_Helper_String object. + * + * @return TeamSpeak3_Helper_String + */ + public function toString() + { + return (!func_num_args()) ? $this->rpl->unescape() : $this->rpl; + } + + /** + * Returns the reply as a standard PHP array where each element represents one item. + * + * @return array + */ + public function toLines() + { + if(!count($this->rpl)) return array(); + + $list = $this->toString(0)->split(TeamSpeak3::SEPARATOR_LIST); + + if(!func_num_args()) + { + for($i = 0; $i < count($list); $i++) $list[$i]->unescape(); + } + + return $list; + } + + /** + * Returns the reply as a standard PHP array where each element represents one item in table format. + * + * @return array + */ + public function toTable() + { + $table = array(); + + foreach($this->toLines(0) as $cells) + { + $pairs = $cells->split(TeamSpeak3::SEPARATOR_CELL); + + if(!func_num_args()) + { + for($i = 0; $i < count($pairs); $i++) $pairs[$i]->unescape(); + } + + $table[] = $pairs; + } + + return $table; + } + + /** + * Returns a multi-dimensional array containing the reply splitted in multiple rows and columns. + * + * @return array + */ + public function toArray() + { + $array = array(); + $table = $this->toTable(1); + + for($i = 0; $i < count($table); $i++) + { + foreach($table[$i] as $pair) + { + if(!count($pair)) + { + continue; + } + + if(!$pair->contains(TeamSpeak3::SEPARATOR_PAIR)) + { + $array[$i][$pair->toString()] = null; + } + else + { + list($ident, $value) = $pair->split(TeamSpeak3::SEPARATOR_PAIR, 2); + + $array[$i][$ident->toString()] = $value->isInt() ? $value->toInt() : (!func_num_args() ? $value->unescape() : $value); + } + } + } + + return $array; + } + + /** + * Returns a multi-dimensional assoc array containing the reply splitted in multiple rows and columns. + * The identifier specified by key will be used while indexing the array. + * + * @param $key + * @return array + */ + public function toAssocArray($ident) + { + $nodes = (func_num_args() > 1) ? $this->toArray(1) : $this->toArray(); + $array = array(); + + foreach($nodes as $node) + { + if(isset($node[$ident])) + { + $array[(is_object($node[$ident])) ? $node[$ident]->toString() : $node[$ident]] = $node; + } + else + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + } + + return $array; + } + + /** + * Returns an array containing the reply splitted in multiple rows and columns. + * + * @return array + */ + public function toList() + { + $array = func_num_args() ? $this->toArray(1) : $this->toArray(); + + if(count($array) == 1) + { + return array_shift($array); + } + + return $array; + } + + /** + * Returns an array containing stdClass objects. + * + * @return ArrayObject + */ + public function toObjectArray() + { + $array = (func_num_args() > 1) ? $this->toArray(1) : $this->toArray(); + + for($i = 0; $i < count($array); $i++) + { + $array[$i] = (object) $array[$i]; + } + + return $array; + } + + /** + * Returns the command used to get this reply. + * + * @return TeamSpeak3_Helper_String + */ + public function getCommandString() + { + return new TeamSpeak3_Helper_String($this->cmd); + } + + /** + * Returns an array of events that occured before or during this reply. + * + * @return array + */ + public function getNotifyEvents() + { + return $this->evt; + } + + /** + * Returns the value for a specified error property. + * + * @param string $ident + * @param mixed $default + * @return mixed + */ + public function getErrorProperty($ident, $default = null) + { + return (array_key_exists($ident, $this->err)) ? $this->err[$ident] : $default; + } + + /** + * Parses a ServerQuery error and throws a TeamSpeak3_Adapter_ServerQuery_Exception object if + * there's an error. + * + * @param string $err + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return void + */ + protected function fetchError($err) + { + $cells = $err->section(TeamSpeak3::SEPARATOR_CELL, 1, 3); + + foreach($cells->split(TeamSpeak3::SEPARATOR_CELL) as $pair) + { + list($ident, $value) = $pair->split(TeamSpeak3::SEPARATOR_PAIR); + + $this->err[$ident->toString()] = $value->isInt() ? $value->toInt() : $value->unescape(); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyError", $this); + + if($this->getErrorProperty("id", 0x00) != 0x00 && $this->exp) + { + if($permid = $this->getErrorProperty("failed_permid")) + { + if($permsid = key($this->con->request("permget permid=" . $permid, FALSE)->toAssocArray("permsid"))) + { + $suffix = " (failed on " . $permsid . ")"; + } + else + { + $suffix = " (failed on " . $this->cmd->section(TeamSpeak3::SEPARATOR_CELL) . " " . $permid . "/0x" . strtoupper(dechex($permid)) . ")"; + } + } + elseif($details = $this->getErrorProperty("extra_msg")) + { + $suffix = " (" . trim($details) . ")"; + } + else + { + $suffix = ""; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception($this->getErrorProperty("msg") . $suffix, $this->getErrorProperty("id")); + } + } + + /** + * Parses a ServerQuery reply and creates a TeamSpeak3_Helper_String object. + * + * @param string $rpl + * @return void + */ + protected function fetchReply($rpl) + { + foreach($rpl as $key => $val) + { + if($val->startsWith(TeamSpeak3::GREET)) + { + unset($rpl[$key]); + } + elseif($val->startsWith(TeamSpeak3::EVENT)) + { + $this->evt[] = new TeamSpeak3_Adapter_ServerQuery_Event($rpl[$key], $this->con); + unset($rpl[$key]); + } + } + + $this->rpl = new TeamSpeak3_Helper_String(implode(TeamSpeak3::SEPARATOR_LIST, $rpl)); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/TSDNS.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/TSDNS.php new file mode 100644 index 0000000..aba617f --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/TSDNS.php @@ -0,0 +1,95 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_TSDNS + * @brief Provides methods to query a TSDNS server. + */ +class TeamSpeak3_Adapter_TSDNS extends TeamSpeak3_Adapter_Abstract +{ + /** + * The TCP port number used by any TSDNS server. + * + * @var integer + */ + protected $default_port = 41144; + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + public function syn() + { + if(!isset($this->options["port"]) || empty($this->options["port"])) $this->options["port"] = $this->default_port; + + $this->initTransport($this->options); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("tsdnsConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_FileTransfer destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->getTransport()->isConnected()) + { + $this->getTransport()->disconnect(); + } + } + + /** + * Queries the TSDNS server for a specified virtual hostname and returns the result. + * + * @param string $tsdns + * @throws TeamSpeak3_Adapter_TSDNS_Exception + * @return TeamSpeak3_Helper_String + */ + public function resolve($tsdns) + { + $this->getTransport()->sendLine($tsdns); + $repl = $this->getTransport()->readLine(); + $this->getTransport()->disconnect(); + + if($repl->section(":", 0)->toInt() == 404) + { + throw new TeamSpeak3_Adapter_TSDNS_Exception("unable to resolve TSDNS hostname (" . $tsdns . ")"); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("tsdnsResolved", $tsdns, $repl); + + return $repl; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/TSDNS/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/TSDNS/Exception.php new file mode 100644 index 0000000..1701479 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/TSDNS/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_TSDNS_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_TSDNS objects. + */ +class TeamSpeak3_Adapter_TSDNS_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Update.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Update.php new file mode 100644 index 0000000..247ee12 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Update.php @@ -0,0 +1,217 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Update + * @brief Provides methods to query the latest TeamSpeak 3 build numbers from the master server. + */ +class TeamSpeak3_Adapter_Update extends TeamSpeak3_Adapter_Abstract +{ + /** + * The IPv4 address or FQDN of the TeamSpeak Systems update server. + * + * @var string + */ + protected $default_host = "update.teamspeak.com"; + + /** + * The UDP port number of the TeamSpeak Systems update server. + * + * @var integer + */ + protected $default_port = 17384; + + /** + * Stores an array containing the latest build numbers (integer timestamps). + * + * @var array + */ + protected $build_datetimes = null; + + /** + * Stores an array containing the latest version strings. + * + * @var array + */ + protected $version_strings = null; + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Update_Exception + * @return void + */ + public function syn() + { + if(!isset($this->options["host"]) || empty($this->options["host"])) $this->options["host"] = $this->default_host; + if(!isset($this->options["port"]) || empty($this->options["port"])) $this->options["port"] = $this->default_port; + + $this->initTransport($this->options, "TeamSpeak3_Transport_UDP"); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + $this->getTransport()->send(TeamSpeak3_Helper_String::fromHex(33)); + + if(!preg_match_all("/,?(\d+)#([0-9a-zA-Z\._-]+),?/", $this->getTransport()->read(96), $matches) || !isset($matches[1]) || !isset($matches[2])) + { + throw new TeamSpeak3_Adapter_Update_Exception("invalid reply from the server"); + } + + $this->build_datetimes = $matches[1]; + $this->version_strings = $matches[2]; + + TeamSpeak3_Helper_Signal::getInstance()->emit("updateConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_Update destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->getTransport()->isConnected()) + { + $this->getTransport()->disconnect(); + } + } + + /** + * Returns the current build number for a specified update channel. Note that since version + * 3.0.0, the build number represents an integer timestamp. $channel must be set to one of + * the following values: + * + * - stable + * - beta + * - alpha + * - server + * + * @param string $channel + * @throws TeamSpeak3_Adapter_Update_Exception + * @return integer + */ + public function getRev($channel = "stable") + { + switch($channel) + { + case "stable": + return isset($this->build_datetimes[0]) ? $this->build_datetimes[0] : null; + + case "beta": + return isset($this->build_datetimes[1]) ? $this->build_datetimes[1] : null; + + case "alpha": + return isset($this->build_datetimes[2]) ? $this->build_datetimes[2] : null; + + case "server": + return isset($this->build_datetimes[3]) ? $this->build_datetimes[3] : null; + + default: + throw new TeamSpeak3_Adapter_Update_Exception("invalid update channel identifier (" . $channel . ")"); + } + } + + /** + * Returns the current version string for a specified update channel. $channel must be set to + * one of the following values: + * + * - stable + * - beta + * - alpha + * - server + * + * @param string $channel + * @throws TeamSpeak3_Adapter_Update_Exception + * @return integer + */ + public function getVersion($channel = "stable") + { + switch($channel) + { + case "stable": + return isset($this->version_strings[0]) ? $this->version_strings[0] : null; + + case "beta": + return isset($this->version_strings[1]) ? $this->version_strings[1] : null; + + case "alpha": + return isset($this->version_strings[2]) ? $this->version_strings[2] : null; + + case "server": + return isset($this->version_strings[3]) ? $this->version_strings[3] : null; + + default: + throw new TeamSpeak3_Adapter_Update_Exception("invalid update channel identifier (" . $channel . ")"); + } + } + + /** + * Alias for getRev() using the 'stable' update channel. + * + * @param string $channel + * @return integer + */ + public function getClientRev() + { + return $this->getRev("stable"); + } + + /** + * Alias for getRev() using the 'server' update channel. + * + * @param string $channel + * @return integer + */ + public function getServerRev() + { + return $this->getRev("server"); + } + + /** + * Alias for getVersion() using the 'stable' update channel. + * + * @param string $channel + * @return integer + */ + public function getClientVersion() + { + return $this->getVersion("stable"); + } + + /** + * Alias for getVersion() using the 'server' update channel. + * + * @param string $channel + * @return integer + */ + public function getServerVersion() + { + return $this->getVersion("server"); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Update/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Update/Exception.php new file mode 100644 index 0000000..a68a447 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Adapter/Update/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Update_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_Update objects. + */ +class TeamSpeak3_Adapter_Update_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Exception.php new file mode 100644 index 0000000..8f4c5d3 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Exception.php @@ -0,0 +1,129 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Exception + * @brief Enhanced exception class for TeamSpeak3 objects. + */ +class TeamSpeak3_Exception extends Exception +{ + /** + * Stores custom error messages. + * + * @var array + */ + protected static $messages = array(); + + /** + * The TeamSpeak3_Exception constructor. + * + * @param string $mesg + * @param integer $code + * @return TeamSpeak3_Exception + */ + public function __construct($mesg, $code = 0x00) + { + parent::__construct($mesg, $code); + + if(array_key_exists((int) $code, self::$messages)) + { + $this->message = $this->prepareCustomMessage(self::$messages[intval($code)]); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("errorException", $this); + } + + /** + * Prepares a custom error message by replacing pre-defined signs with given values. + * + * @param TeamSpeak3_Helper_String $mesg + * @return TeamSpeak3_Helper_String + */ + protected function prepareCustomMessage(TeamSpeak3_Helper_String $mesg) + { + $args = array( + "code" => $this->getCode(), + "mesg" => $this->getMessage(), + "line" => $this->getLine(), + "file" => $this->getFile(), + ); + + return $mesg->arg($args)->toString(); + } + + /** + * Registers a custom error message to $code. + * + * @param integer $code + * @param string $mesg + * @throws TeamSpeak3_Exception + * @return void + */ + public static function registerCustomMessage($code, $mesg) + { + if(array_key_exists((int) $code, self::$messages)) + { + throw new self("custom message for code 0x" . strtoupper(dechex($code)) . " is already registered"); + } + + if(!is_string($mesg)) + { + throw new self("custom message for code 0x" . strtoupper(dechex($code)) . " must be a string"); + } + + self::$messages[(int) $code] = new TeamSpeak3_Helper_String($mesg); + } + + /** + * Unregisters a custom error message from $code. + * + * @param integer $code + * @throws TeamSpeak3_Exception + * @return void + */ + public static function unregisterCustomMessage($code) + { + if(!array_key_exists((int) $code, self::$messages)) + { + throw new self("custom message for code 0x" . strtoupper(dechex($code)) . " is not registered"); + } + + unset(self::$messages[(int) $code]); + } + + /** + * Returns the class from which the exception was thrown. + * + * @return string + */ + public function getSender() + { + $trace = $this->getTrace(); + + return (isset($trace[0]["class"])) ? $trace[0]["class"] : "{main}"; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Char.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Char.php new file mode 100644 index 0000000..cf9e853 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Char.php @@ -0,0 +1,269 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Char + * @brief Helper class for char handling. + */ +class TeamSpeak3_Helper_Char +{ + /** + * Stores the original character. + * + * @var string + */ + protected $char = null; + + /** + * The TeamSpeak3_Helper_Char constructor. + * + * @param string $var + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_Char + */ + public function __construct($char) + { + if(strlen($char) != 1) + { + throw new TeamSpeak3_Helper_Exception("char parameter may not contain more or less than one character"); + } + + $this->char = strval($char); + } + + /** + * Returns true if the character is a letter. + * + * @return boolean + */ + public function isLetter() + { + return ctype_alpha($this->char); + } + + /** + * Returns true if the character is a decimal digit. + * + * @return boolean + */ + public function isDigit() + { + return ctype_digit($this->char); + } + + /** + * Returns true if the character is a space. + * + * @return boolean + */ + public function isSpace() + { + return ctype_space($this->char); + } + + /** + * Returns true if the character is a mark. + * + * @return boolean + */ + public function isMark() + { + return ctype_punct($this->char); + } + + /** + * Returns true if the character is a control character (i.e. "\t"). + * + * @return boolean + */ + public function isControl() + { + return ctype_cntrl($this->char); + } + + /** + * Returns true if the character is a printable character. + * + * @return boolean + */ + public function isPrintable() + { + return ctype_print($this->char); + } + + /** + * Returns true if the character is the Unicode character 0x0000 ("\0"). + * + * @return boolean + */ + public function isNull() + { + return ($this->char === "\0") ? TRUE : FALSE; + } + + /** + * Returns true if the character is an uppercase letter. + * + * @return boolean + */ + public function isUpper() + { + return ($this->char === strtoupper($this->char)) ? TRUE : FALSE; + } + + /** + * Returns true if the character is a lowercase letter. + * + * @return boolean + */ + public function isLower() + { + return ($this->char === strtolower($this->char)) ? TRUE : FALSE; + } + + /** + * Returns the uppercase equivalent if the character is lowercase. + * + * @return TeamSpeak3_Helper_Char + */ + public function toUpper() + { + return ($this->isUpper()) ? $this : new self(strtoupper($this)); + } + + /** + * Returns the lowercase equivalent if the character is uppercase. + * + * @return TeamSpeak3_Helper_Char + */ + public function toLower() + { + return ($this->isLower()) ? $this : new self(strtolower($this)); + } + + /** + * Returns the ascii value of the character. + * + * @return integer + */ + public function toAscii() + { + return ord($this->char); + } + + /** + * Returns the Unicode value of the character. + * + * @return integer + */ + public function toUnicode() + { + $h = ord($this->char{0}); + + if($h <= 0x7F) + { + return $h; + } + else if($h < 0xC2) + { + return FALSE; + } + else if($h <= 0xDF) + { + return ($h & 0x1F) << 6 | (ord($this->char{1}) & 0x3F); + } + else if($h <= 0xEF) + { + return ($h & 0x0F) << 12 | (ord($this->char{1}) & 0x3F) << 6 | (ord($this->char{2}) & 0x3F); + } + else if($h <= 0xF4) + { + return ($h & 0x0F) << 18 | (ord($this->char{1}) & 0x3F) << 12 | (ord($this->char{2}) & 0x3F) << 6 | (ord($this->char{3}) & 0x3F); + } + else + { + return FALSE; + } + } + + /** + * Returns the hexadecimal value of the char. + * + * @return string + */ + public function toHex() + { + return strtoupper(dechex($this->toAscii())); + } + + /** + * Returns the TeamSpeak3_Helper_Char based on a given hex value. + * + * @param string $hex + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_Char + */ + public static function fromHex($hex) + { + if(strlen($hex) != 2) + { + throw new TeamSpeak3_Helper_Exception("given parameter '" . $hex . "' is not a valid hexadecimal number"); + } + + return new self(chr(hexdec($hex))); + } + + /** + * Returns the character as a standard string. + * + * @return string + */ + public function toString() + { + return $this->char; + } + + /** + * Returns the integer value of the character. + * + * @return integer + */ + public function toInt() + { + return intval($this->char); + } + + /** + * Returns the character as a standard string. + * + * @return string + */ + public function __toString() + { + return $this->char; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Convert.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Convert.php new file mode 100644 index 0000000..6b8979f --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Convert.php @@ -0,0 +1,349 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Convert + * @brief Helper class for data conversion. + */ +class TeamSpeak3_Helper_Convert +{ + /** + * Converts bytes to a human readable value. + * + * @param integer $bytes + * @return string + */ + public static function bytes($bytes) + { + $kbytes = sprintf("%.02f", $bytes/1024); + $mbytes = sprintf("%.02f", $kbytes/1024); + $gbytes = sprintf("%.02f", $mbytes/1024); + $tbytes = sprintf("%.02f", $gbytes/1024); + + if($tbytes >= 1) + return $tbytes . " TB"; + if($gbytes >= 1) + return $gbytes . " GB"; + if($mbytes >= 1) + return $mbytes . " MB"; + if($kbytes >= 1) + return $kbytes . " KB"; + + return $bytes . " B"; + } + + /** + * Converts seconds/milliseconds to a human readable value. + * + * @param integer $seconds + * @param boolean $is_ms + * @param string $format + * @return string + */ + public static function seconds($seconds, $is_ms = FALSE, $format = "%dD %02d:%02d:%02d") + { + if($is_ms) $seconds = $seconds/1000; + + return sprintf($format, $seconds/60/60/24, ($seconds/60/60)%24, ($seconds/60)%60, $seconds%60); + } + + /** + * Converts a given codec ID to a human readable name. + * + * @param integer $codec + * @return string + */ + public static function codec($codec) + { + if($codec == TeamSpeak3::CODEC_SPEEX_NARROWBAND) + return "Speex Narrowband"; + if($codec == TeamSpeak3::CODEC_SPEEX_WIDEBAND) + return "Speex Wideband"; + if($codec == TeamSpeak3::CODEC_SPEEX_ULTRAWIDEBAND) + return "Speex Ultra-Wideband"; + if($codec == TeamSpeak3::CODEC_CELT_MONO) + return "CELT Mono"; + if($codec == TeamSpeak3::CODEC_OPUS_VOICE) + return "Opus Voice"; + if($codec == TeamSpeak3::CODEC_OPUS_MUSIC) + return "Opus Music"; + + return "Unknown"; + } + + /** + * Converts a given group type ID to a human readable name. + * + * @param integer $type + * @return string + */ + public static function groupType($type) + { + if($type == TeamSpeak3::GROUP_DBTYPE_TEMPLATE) + return "Template"; + if($type == TeamSpeak3::GROUP_DBTYPE_REGULAR) + return "Regular"; + if($type == TeamSpeak3::GROUP_DBTYPE_SERVERQUERY) + return "ServerQuery"; + + return "Unknown"; + } + + /** + * Converts a given permission type ID to a human readable name. + * + * @param integer $type + * @return string + */ + public static function permissionType($type) + { + if($type == TeamSpeak3::PERM_TYPE_SERVERGROUP) + return "Server Group"; + if($type == TeamSpeak3::PERM_TYPE_CLIENT) + return "Client"; + if($type == TeamSpeak3::PERM_TYPE_CHANNEL) + return "Channel"; + if($type == TeamSpeak3::PERM_TYPE_CHANNELGROUP) + return "Channel Group"; + if($type == TeamSpeak3::PERM_TYPE_CHANNELCLIENT) + return "Channel Client"; + + return "Unknown"; + } + + /** + * Converts a given permission category value to a human readable name. + * + * @param integer $pcat + * @return string + */ + public static function permissionCategory($pcat) + { + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL) + return "Global"; + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL_INFORMATION) + return "Global / Information"; + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL_SERVER_MGMT) + return "Global / Virtual Server Management"; + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL_ADM_ACTIONS) + return "Global / Administration"; + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL_SETTINGS) + return "Global / Settings"; + if($pcat == TeamSpeak3::PERM_CAT_SERVER) + return "Virtual Server"; + if($pcat == TeamSpeak3::PERM_CAT_SERVER_INFORMATION) + return "Virtual Server / Information"; + if($pcat == TeamSpeak3::PERM_CAT_SERVER_ADM_ACTIONS) + return "Virtual Server / Administration"; + if($pcat == TeamSpeak3::PERM_CAT_SERVER_SETTINGS) + return "Virtual Server / Settings"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL) + return "Channel"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_INFORMATION) + return "Channel / Information"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_CREATE) + return "Channel / Create"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_MODIFY) + return "Channel / Modify"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_DELETE) + return "Channel / Delete"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_ACCESS) + return "Channel / Access"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP) + return "Group"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP_INFORMATION) + return "Group / Information"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP_CREATE) + return "Group / Create"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP_MODIFY) + return "Group / Modify"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP_DELETE) + return "Group / Delete"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT) + return "Client"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT_INFORMATION) + return "Client / Information"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT_ADM_ACTIONS) + return "Client / Admin"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT_BASICS) + return "Client / Basics"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT_MODIFY) + return "Client / Modify"; + if($pcat == TeamSpeak3::PERM_CAT_FILETRANSFER) + return "File Transfer"; + if($pcat == TeamSpeak3::PERM_CAT_NEEDED_MODIFY_POWER) + return "Grant"; + + return "Unknown"; + } + + /** + * Converts a given log level ID to a human readable name and vice versa. + * + * @param mixed $level + * @return string + */ + public static function logLevel($level) + { + if(is_numeric($level)) + { + if($level == TeamSpeak3::LOGLEVEL_CRITICAL) + return "CRITICAL"; + if($level == TeamSpeak3::LOGLEVEL_ERROR) + return "ERROR"; + if($level == TeamSpeak3::LOGLEVEL_DEBUG) + return "DEBUG"; + if($level == TeamSpeak3::LOGLEVEL_WARNING) + return "WARNING"; + if($level == TeamSpeak3::LOGLEVEL_INFO) + return "INFO"; + + return "DEVELOP"; + } + else + { + if(strtoupper($level) == "CRITICAL") + return TeamSpeak3::LOGLEVEL_CRITICAL; + if(strtoupper($level) == "ERROR") + return TeamSpeak3::LOGLEVEL_ERROR; + if(strtoupper($level) == "DEBUG") + return TeamSpeak3::LOGLEVEL_DEBUG; + if(strtoupper($level) == "WARNING") + return TeamSpeak3::LOGLEVEL_WARNING; + if(strtoupper($level) == "INFO") + return TeamSpeak3::LOGLEVEL_INFO; + + return TeamSpeak3::LOGLEVEL_DEVEL; + } + } + + /** + * Converts a specified log entry string into an array containing the data. + * + * @param string $entry + * @return array + */ + public static function logEntry($entry) + { + $parts = explode("|", $entry, 5); + $array = array(); + + if(count($parts) != 5) + { + $array["timestamp"] = 0; + $array["level"] = TeamSpeak3::LOGLEVEL_ERROR; + $array["channel"] = "ParamParser"; + $array["server_id"] = ""; + $array["msg"] = TeamSpeak3_Helper_String::factory("convert error (" . trim($entry) . ")"); + $array["msg_plain"] = $entry; + $array["malformed"] = TRUE; + } + else + { + $array["timestamp"] = strtotime(trim($parts[0])); + $array["level"] = self::logLevel(trim($parts[1])); + $array["channel"] = trim($parts[2]); + $array["server_id"] = trim($parts[3]); + $array["msg"] = TeamSpeak3_Helper_String::factory(trim($parts[4])); + $array["msg_plain"] = $entry; + $array["malformed"] = FALSE; + } + + return $array; + } + + /** + * Converts a given string to a ServerQuery password hash. + * + * @param string $plain + * @return string + */ + public static function password($plain) + { + return base64_encode(sha1($plain, TRUE)); + } + + /** + * Returns a client-like formatted version of the TeamSpeak 3 version string. + * + * @param string $version + * @param string $format + * @return string + */ + public static function version($version, $format = "Y-m-d h:i:s") + { + if(!$version instanceof TeamSpeak3_Helper_String) + { + $version = new TeamSpeak3_Helper_String($version); + } + + $buildno = $version->section("[", 1)->filterDigits()->toInt(); + + return ($buildno <= 15001) ? $version : $version->section("[")->append("(" . date($format, $buildno) . ")"); + } + + /** + * Returns a client-like short-formatted version of the TeamSpeak 3 version string. + * + * @param string $version + * @return string + */ + public static function versionShort($version) + { + if(!$version instanceof TeamSpeak3_Helper_String) + { + $version = new TeamSpeak3_Helper_String($version); + } + + return $version->section(" ", 0); + } + + /** + * Tries to detect the type of an image by a given string and returns it. + * + * @param string $binary + * @return string + */ + public static function imageMimeType($binary) + { + if(!preg_match('/\A(?:(\xff\xd8\xff)|(GIF8[79]a)|(\x89PNG\x0d\x0a)|(BM)|(\x49\x49(\x2a\x00|\x00\x4a))|(FORM.{4}ILBM))/', $binary, $matches)) + { + return "application/octet-stream"; + } + + $type = array( + 1 => "image/jpeg", + 2 => "image/gif", + 3 => "image/png", + 4 => "image/x-windows-bmp", + 5 => "image/tiff", + 6 => "image/x-ilbm", + ); + + return $type[count($matches)-1]; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Crypt.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Crypt.php new file mode 100644 index 0000000..dff571c --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Crypt.php @@ -0,0 +1,482 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Crypt + * @brief Helper class for data encryption. + */ +class TeamSpeak3_Helper_Crypt +{ + /** + * Stores the secret passphrase to encrypt or decrypt a given string. + * + * @var string + */ + protected $passphrase = null; + + /** + * Stores an array containing 18 32-bit entries. + * + * @var array + */ + protected $p = array(); + + /** + * Stores an array containing 4 sub-arrays with 256 32-bit entries. + * + * @var array + */ + protected $s = array(); + + /** + * The TeamSpeak3_Helper_Crypt constructor. + * + * @param string $secret + * @return TeamSpeak3_Helper_Crypt + */ + public function __construct($secret) + { + $this->setDefaultKeys(); + $this->setSecretKey($secret); + } + + /** + * Encrypts a given string. + * + * @param string $string + * @return string + */ + public function encrypt($string) + { + $string = trim($string); + $encryp = ""; + $length = strlen($string); + $string .= str_repeat(chr(0), (8-($length%8))%8); + + for($i = 0; $i < $length; $i += 8) + { + list(,$xl,$xr) = unpack("N2", substr($string, $i, 8)); + $this->encipher($xl, $xr); + $encryp .= pack("N2", $xl, $xr); + } + + return base64_encode($encryp); + } + + /** + * Decrypts a given string. + * + * @param string $string + * @return string + */ + public function decrypt($string) + { + $string = base64_decode($string); + $decryp = ""; + $length = strlen($string); + $string .= str_repeat(chr(0), (8-($length%8))%8); + + for($i = 0; $i < $length; $i += 8) + { + list(,$xl,$xr) = unpack("N2", substr($string, $i, 8)); + $this->decipher($xl, $xr); + $decryp .= pack("N2", $xl, $xr); + } + + return trim($decryp); + } + + /** + * Enciphers a single 64-bit block. + * + * @param integer $xl + * @param integer $xr + */ + protected function encipher(&$xl, &$xr) + { + for($i = 0; $i < 16; $i++) + { + $temp = $xl ^ $this->p[$i]; + $xl = ((($this->s[0][($temp>>24) & 255] + $this->s[1][($temp>>16) & 255]) ^ $this->s[2][($temp>>8) & 255]) + $this->s[3][$temp & 255]) ^ $xr; + $xr = $temp; + } + + $xr = $xl ^ $this->p[16]; + $xl = $temp ^ $this->p[17]; + } + + /** + * Deciphers a single 64-bit block + * + * @param integer $xl + * @param integer $xr + * @return void + */ + protected function decipher(&$xl, &$xr) + { + for($i = 17; $i > 1; $i--) + { + $temp = $xl ^ $this->p[$i]; + $xl = ((($this->s[0][($temp>>24) & 255] + $this->s[1][($temp>>16) & 255]) ^ $this->s[2][($temp>>8) & 255]) + $this->s[3][$temp & 255]) ^ $xr; + $xr = $temp; + } + + $xr = $xl ^ $this->p[1]; + $xl = $temp ^ $this->p[0]; + } + + /** + * Sets the secret key using the specified pasphrase. + * + * @param string $passphrase + * @throws Habitat_Exception + * @return void + */ + protected function setSecretKey($passphrase) + { + $length = strlen($passphrase); + + if(strlen($passphrase) < 1 || strlen($passphrase) > 56) + { + throw new TeamSpeak3_Helper_Exception("secret passphrase must contain at least one but less than 56 characters"); + } + + $k = 0; + $data = 0; + $datal = 0; + $datar = 0; + + for($i = 0; $i < 18; $i++) + { + $data = 0; + for($j = 4; $j > 0; $j--) + { + $data = $data << 8 | ord($passphrase{$k}); + $k = ($k+1) % $length; + } + $this->p[$i] ^= $data; + } + + + for($i = 0; $i <= 16; $i += 2) + { + $this->encipher($datal, $datar); + $this->p[$i] = $datal; + $this->p[$i+1] = $datar; + } + + foreach($this->s as $key => $val) + { + for ($i = 0; $i < 256; $i += 2) + { + $this->encipher($datal, $datar); + $this->s[$key][$i] = $datal; + $this->s[$key][$i+1] = $datar; + } + } + } + + /** + * Sets the defult p and s keys. + * + * @return void + */ + protected function setDefaultKeys() + { + $this->p = array( + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, + 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B, + ); + $this->s = array( + array( + 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A + ), + array( + 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 + ), + array( + 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 + ), + array( + 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 + ) + ); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Exception.php new file mode 100644 index 0000000..23796cd --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Exception + * @brief Enhanced exception class for TeamSpeak3_Helper_* objects. + */ +class TeamSpeak3_Helper_Exception extends TeamSpeak3_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Profiler.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Profiler.php new file mode 100644 index 0000000..bf9d7f7 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Profiler.php @@ -0,0 +1,101 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Profiler + * @brief Helper class for profiler handling. + */ +class TeamSpeak3_Helper_Profiler +{ + /** + * Stores various timers for code profiling. + * + * @var array + */ + protected static $timers = array(); + + /** + * Inits a timer. + * + * @param string $name + * @return void + */ + public static function init($name = "default") + { + self::$timers[$name] = new TeamSpeak3_Helper_Profiler_Timer($name); + } + + /** + * Starts a timer. + * + * @param string $name + * @return void + */ + public static function start($name = "default") + { + if(array_key_exists($name, self::$timers)) + { + self::$timers[$name]->start(); + } + else + { + self::$timers[$name] = new TeamSpeak3_Helper_Profiler_Timer($name); + } + } + + /** + * Stops a timer. + * + * @param string $name + * @return void + */ + public static function stop($name = "default") + { + if(!array_key_exists($name, self::$timers)) + { + self::init($name); + } + + self::$timers[$name]->stop(); + } + + /** + * Returns a timer. + * + * @param string $name + * @return TeamSpeak3_Helper_Profiler_Timer + */ + public static function get($name = "default") + { + if(!array_key_exists($name, self::$timers)) + { + self::init($name); + } + + return self::$timers[$name]; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Profiler/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Profiler/Exception.php new file mode 100644 index 0000000..ba770bc --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Profiler/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Profiler_Exception + * @brief Enhanced exception class for TeamSpeak3_Helper_Profiler objects. + */ +class TeamSpeak3_Helper_Profiler_Exception extends TeamSpeak3_Helper_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Profiler/Timer.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Profiler/Timer.php new file mode 100644 index 0000000..3ee87cf --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Profiler/Timer.php @@ -0,0 +1,154 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Profiler_Timer + * @brief Helper class providing profiler timers. + */ +class TeamSpeak3_Helper_Profiler_Timer +{ + /** + * Indicates wether the timer is running or not. + * + * @var boolean + */ + protected $running = FALSE; + + /** + * Stores the timestamp when the timer was last started. + * + * @var integer + */ + protected $started = 0; + + /** + * Stores the timer name. + * + * @var string + */ + protected $name = null; + + /** + * Stores various information about the server environment. + * + * @var array + */ + protected $data = array(); + + /** + * The TeamSpeak3_Helper_Profiler_Timer constructor. + * + * @param string $name + * @return TeamSpeak3_Helper_Profiler_Timer + */ + public function __construct($name) + { + $this->name = (string) $name; + + $this->data["runtime"] = 0; + $this->data["realmem"] = 0; + $this->data["emalloc"] = 0; + + $this->start(); + } + + /** + * Starts the timer. + * + * @return void + */ + public function start() + { + if($this->isRunning()) return; + + $this->data["realmem_start"] = memory_get_usage(TRUE); + $this->data["emalloc_start"] = memory_get_usage(); + + $this->started = microtime(TRUE); + $this->running = TRUE; + } + + /** + * Stops the timer. + * + * @return void + */ + public function stop() + { + if(!$this->isRunning()) return; + + $this->data["runtime"] += microtime(TRUE) - $this->started; + $this->data["realmem"] += memory_get_usage(TRUE) - $this->data["realmem_start"]; + $this->data["emalloc"] += memory_get_usage() - $this->data["emalloc_start"]; + + $this->started = 0; + $this->running = FALSE; + } + + /** + * Return the timer runtime. + * + * @return mixed + */ + public function getRuntime() + { + if($this->isRunning()) + { + $this->stop(); + $this->start(); + } + + return $this->data["runtime"]; + } + + /** + * Returns the amount of memory allocated to PHP in bytes. + * + * @param boolean $realmem + * @return integer + */ + public function getMemUsage($realmem = FALSE) + { + if($this->isRunning()) + { + $this->stop(); + $this->start(); + } + + return ($realmem !== FALSE) ? $this->data["realmem"] : $this->data["emalloc"]; + } + + /** + * Returns TRUE if the timer is running. + * + * @return boolean + */ + public function isRunning() + { + return $this->running; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal.php new file mode 100644 index 0000000..40010c7 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal.php @@ -0,0 +1,213 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Signal + * @brief Helper class for signal slots. + */ +class TeamSpeak3_Helper_Signal +{ + /** + * Stores the TeamSpeak3_Helper_Signal object. + * + * @var TeamSpeak3_Helper_Signal + */ + protected static $instance = null; + + /** + * Stores subscribed signals and their slots. + * + * @var array + */ + protected $sigslots = array(); + + /** + * Emits a signal with a given set of parameters. + * + * @param string $signal + * @param mixed $params + * @return mixed + */ + public function emit($signal, $params = null) + { + if(!$this->hasHandlers($signal)) + { + return; + } + + if(!is_array($params)) + { + $params = func_get_args(); + $params = array_slice($params, 1); + } + + foreach($this->sigslots[$signal] as $slot) + { + $return = $slot->call($params); + } + + return $return; + } + + /** + * Generates a MD5 hash based on a given callback. + * + * @param mixed $callback + * @param string + * @return void + */ + public function getCallbackHash($callback) + { + if(!is_callable($callback, TRUE, $callable_name)) + { + throw new TeamSpeak3_Helper_Signal_Exception("invalid callback specified"); + } + + return md5($callable_name); + } + + /** + * Subscribes to a signal and returns the signal handler. + * + * @param string $signal + * @param mixed $callback + * @return TeamSpeak3_Helper_Signal_Handler + */ + public function subscribe($signal, $callback) + { + if(empty($this->sigslots[$signal])) + { + $this->sigslots[$signal] = array(); + } + + $index = $this->getCallbackHash($callback); + + if(!array_key_exists($index, $this->sigslots[$signal])) + { + $this->sigslots[$signal][$index] = new TeamSpeak3_Helper_Signal_Handler($signal, $callback); + } + + return $this->sigslots[$signal][$index]; + } + + /** + * Unsubscribes from a signal. + * + * @param string $signal + * @param mixed $callback + * @return void + */ + public function unsubscribe($signal, $callback = null) + { + if(!$this->hasHandlers($signal)) + { + return; + } + + if($callback !== null) + { + $index = $this->getCallbackHash($callback); + + if(!array_key_exists($index, $this->sigslots[$signal])) + { + return; + } + + unset($this->sigslots[$signal][$index]); + } + else + { + unset($this->sigslots[$signal]); + } + } + + /** + * Returns all registered signals. + * + * @return array + */ + public function getSignals() + { + return array_keys($this->sigslots); + } + + /** + * Returns TRUE there are slots subscribed for a specified signal. + * + * @param string $signal + * @return boolean + */ + public function hasHandlers($signal) + { + return empty($this->sigslots[$signal]) ? FALSE : TRUE; + } + + /** + * Returns all slots for a specified signal. + * + * @param string $signal + * @return array + */ + public function getHandlers($signal) + { + if(!$this->hasHandlers($signal)) + { + return $this->sigslots[$signal]; + } + + return array(); + } + + /** + * Clears all slots for a specified signal. + * + * @param string $signal + * @return void + */ + public function clearHandlers($signal) + { + if(!$this->hasHandlers($signal)) + { + unset($this->sigslots[$signal]); + } + } + + /** + * Returns a singleton instance of TeamSpeak3_Helper_Signal. + * + * @return TeamSpeak3_Helper_Signal + */ + public static function getInstance() + { + if(self::$instance === null) + { + self::$instance = new self(); + } + + return self::$instance; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal/Exception.php new file mode 100644 index 0000000..70c1e7f --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Signal_Exception + * @brief Enhanced exception class for TeamSpeak3_Helper_Signal objects. + */ +class TeamSpeak3_Helper_Signal_Exception extends TeamSpeak3_Helper_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal/Handler.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal/Handler.php new file mode 100644 index 0000000..0050b21 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal/Handler.php @@ -0,0 +1,78 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Signal_Handler + * @brief Helper class providing handler functions for signals. + */ +class TeamSpeak3_Helper_Signal_Handler +{ + /** + * Stores the name of the subscribed signal. + * + * @var string + */ + protected $signal = null; + + /** + * Stores the callback function for the subscribed signal. + * + * @var mixed + */ + protected $callback = null; + + /** + * The TeamSpeak3_Helper_Signal_Handler constructor. + * + * @param string $signal + * @param mixed $callback + * @throws TeamSpeak3_Helper_Signal_Exception + * @return TeamSpeak3_Helper_Signal_Handler + */ + public function __construct($signal, $callback) + { + $this->signal = (string) $signal; + + if(!is_callable($callback)) + { + throw new TeamSpeak3_Helper_Signal_Exception("invalid callback specified for signal '" . $signal . "'"); + } + + $this->callback = $callback; + } + + /** + * Invoke the signal handler. + * + * @param array $args + * @return mixed + */ + public function call(array $args = array()) + { + return call_user_func_array($this->callback, $args); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal/Interface.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal/Interface.php new file mode 100644 index 0000000..854b7d5 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Signal/Interface.php @@ -0,0 +1,353 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Signal_Interface + * @brief Interface class describing the layout for TeamSpeak3_Helper_Signal callbacks. + */ +interface TeamSpeak3_Helper_Signal_Interface +{ + /** + * Possible callback for 'Connected' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryConnected", array($object, "onConnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferConnected", array($object, "onConnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistConnected", array($object, "onConnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateConnected", array($object, "onConnect")); + * + * @param TeamSpeak3_Adapter_Abstract $adapter + * @return void + */ + public function onConnect(TeamSpeak3_Adapter_Abstract $adapter); + + /** + * Possible callback for 'Disconnected' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryDisconnected", array($object, "onDisconnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDisconnected", array($object, "onDisconnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistDisconnected", array($object, "onDisconnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateDisconnected", array($object, "onDisconnect")); + * + * @return void + */ + public function onDisconnect(); + + /** + * Possible callback for 'serverqueryCommandStarted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryCommandStarted", array($object, "onCommandStarted")); + * + * @param string $cmd + * @return void + */ + public function onCommandStarted($cmd); + + /** + * Possible callback for 'serverqueryCommandFinished' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryCommandFinished", array($object, "onCommandFinished")); + * + * @param string $cmd + * @param TeamSpeak3_Adapter_ServerQuery_Reply $reply + * @return void + */ + public function onCommandFinished($cmd, TeamSpeak3_Adapter_ServerQuery_Reply $reply); + + /** + * Possible callback for 'notifyEvent' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyEvent", array($object, "onEvent")); + * + * @param TeamSpeak3_Adapter_ServerQuery_Event $event + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onEvent(TeamSpeak3_Adapter_ServerQuery_Event $event, TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyError' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyError", array($object, "onError")); + * + * @param TeamSpeak3_Adapter_ServerQuery_Reply $reply + * @return void + */ + public function onError(TeamSpeak3_Adapter_ServerQuery_Reply $reply); + + /** + * Possible callback for 'notifyServerselected' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServerselected", array($object, "onServerselected")); + * + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onServerselected(TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyServercreated' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServercreated", array($object, "onServercreated")); + * + * @param TeamSpeak3_Node_Host $host + * @param integer $sid + * @return void + */ + public function onServercreated(TeamSpeak3_Node_Host $host, $sid); + + /** + * Possible callback for 'notifyServerdeleted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServerdeleted", array($object, "onServerdeleted")); + * + * @param TeamSpeak3_Node_Host $host + * @param integer $sid + * @return void + */ + public function onServerdeleted(TeamSpeak3_Node_Host $host, $sid); + + /** + * Possible callback for 'notifyServerstarted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServerstarted", array($object, "onServerstarted")); + * + * @param TeamSpeak3_Node_Host $host + * @param integer $sid + * @return void + */ + public function onServerstarted(TeamSpeak3_Node_Host $host, $sid); + + /** + * Possible callback for 'notifyServerstopped' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServerstopped", array($object, "onServerstopped")); + * + * @param TeamSpeak3_Node_Host $host + * @param integer $sid + * @return void + */ + public function onServerstopped(TeamSpeak3_Node_Host $host, $sid); + + /** + * Possible callback for 'notifyServershutdown' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServershutdown", array($object, "onServershutdown")); + * + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onServershutdown(TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyLogin' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyLogin", array($object, "onLogin")); + * + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onLogin(TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyLogout' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyLogout", array($object, "onLogout")); + * + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onLogout(TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyTokencreated' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyTokencreated", array($object, "onTokencreated")); + * + * @param TeamSpeak3_Node_Server $server + * @param string $token + * @return void + */ + public function onTokencreated(TeamSpeak3_Node_Server $server, $token); + + /** + * Possible callback for 'filetransferHandshake' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferHandshake", array($object, "onFtHandshake")); + * + * @param TeamSpeak3_Adapter_FileTransfer $adapter + * @return void + */ + public function onFtHandshake(TeamSpeak3_Adapter_FileTransfer $adapter); + + /** + * Possible callback for 'filetransferUploadStarted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferUploadStarted", array($object, "onFtUploadStarted")); + * + * @param string $ftkey + * @param integer $seek + * @param integer $size + * @return void + */ + public function onFtUploadStarted($ftkey, $seek, $size); + + /** + * Possible callback for 'filetransferUploadProgress' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferUploadProgress", array($object, "onFtUploadProgress")); + * + * @param string $ftkey + * @param integer $seek + * @param integer $size + * @return void + */ + public function onFtUploadProgress($ftkey, $seek, $size); + + /** + * Possible callback for 'filetransferUploadFinished' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferUploadFinished", array($object, "onFtUploadFinished")); + * + * @param string $ftkey + * @param integer $seek + * @param integer $size + * @return void + */ + public function onFtUploadFinished($ftkey, $seek, $size); + + /** + * Possible callback for 'filetransferDownloadStarted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDownloadStarted", array($object, "onFtDownloadStarted")); + * + * @param string $ftkey + * @param integer $buff + * @param integer $size + * @return void + */ + public function onFtDownloadStarted($ftkey, $buff, $size); + + /** + * Possible callback for 'filetransferDownloadProgress' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDownloadProgress", array($object, "onFtDownloadProgress")); + * + * @param string $ftkey + * @param integer $buff + * @param integer $size + * @return void + */ + public function onFtDownloadProgress($ftkey, $buff, $size); + + /** + * Possible callback for 'filetransferDownloadFinished' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDownloadFinished", array($object, "onFtDownloadFinished")); + * + * @param string $ftkey + * @param integer $buff + * @param integer $size + * @return void + */ + public function onFtDownloadFinished($ftkey, $buff, $size); + + /** + * Possible callback for 'DataRead' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryDataRead", array($object, "onDebugDataRead")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDataRead", array($object, "onDebugDataRead")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistDataRead", array($object, "onDebugDataRead")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateDataRead", array($object, "onDebugDataRead")); + * + * @param string $data + * @return void + */ + public function onDebugDataRead($data); + + /** + * Possible callback for 'DataSend' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryDataSend", array($object, "onDebugDataSend")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDataSend", array($object, "onDebugDataSend")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistDataSend", array($object, "onDebugDataSend")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateDataSend", array($object, "onDebugDataSend")); + * + * @param string $data + * @return void + */ + public function onDebugDataSend($data); + + /** + * Possible callback for 'WaitTimeout' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryWaitTimeout", array($object, "onWaitTimeout")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferWaitTimeout", array($object, "onWaitTimeout")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistWaitTimeout", array($object, "onWaitTimeout")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateWaitTimeout", array($object, "onWaitTimeout")); + * + * @param integer $time + * @param TeamSpeak3_Adapter_Abstract $adapter + * @return void + */ + public function onWaitTimeout($time, TeamSpeak3_Adapter_Abstract $adapter); + + /** + * Possible callback for 'errorException' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("errorException", array($object, "onException")); + * + * @param TeamSpeak3_Exception $e + * @return void + */ + public function onException(TeamSpeak3_Exception $e); +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/String.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/String.php new file mode 100644 index 0000000..08e7483 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/String.php @@ -0,0 +1,939 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_String + * @brief Helper class for string handling. + */ +class TeamSpeak3_Helper_String implements ArrayAccess, Iterator, Countable +{ + /** + * Stores the original string. + * + * @var string + */ + protected $string; + + /** + * @ignore + */ + protected $position = 0; + + /** + * The TeamSpeak3_Helper_String constructor. + * + * @param string $string + * @return TeamSpeak3_Helper_String + */ + public function __construct($string) + { + $this->string = (string) $string; + } + + /** + * Returns a TeamSpeak3_Helper_String object for thegiven string. + * + * @param string $string + * @return TeamSpeak3_Helper_String + */ + public static function factory($string) + { + return new self($string); + } + + /** + * Replaces every occurrence of the string $search with the string $replace. + * + * @param string $search + * @param string $replace + * @param boolean $caseSensitivity + * @return TeamSpeak3_Helper_String + */ + public function replace($search, $replace, $caseSensitivity = TRUE) + { + if($caseSensitivity) + { + $this->string = str_replace($search, $replace, $this->string); + } + else + { + $this->string = str_ireplace($search, $replace, $this->string); + } + + return $this; + } + + /** + * This function replaces indexed or associative signs with given values. + * + * @param array $args + * @param string $char + * @return TeamSpeak3_Helper_String + */ + public function arg(array $args, $char = "%") + { + $args = array_reverse($args, TRUE); + + foreach($args as $key => $val) + { + $args[$char . $key] = $val; + unset($args[$key]); + } + + $this->string = strtr($this->string, $args); + + return $this; + } + + /** + * Returns true if the string starts with $pattern. + * + * @param string $pattern + * @return boolean + */ + public function startsWith($pattern) + { + return (substr($this->string, 0, strlen($pattern)) == $pattern) ? TRUE : FALSE; + } + + /** + * Returns true if the string ends with $pattern. + * + * @param string $pattern + * @return boolean + */ + public function endsWith($pattern) + { + return (substr($this->string, strlen($pattern)*-1) == $pattern) ? TRUE : FALSE; + } + + /** + * Returns the position of the first occurrence of a char in a string. + * + * @param string $needle + * @return integer + */ + public function findFirst($needle) + { + return strpos($this->string, $needle); + } + + /** + * Returns the position of the last occurrence of a char in a string. + * + * @param string $needle + * @return integer + */ + public function findLast($needle) + { + return strrpos($this->string, $needle); + } + + /** + * Returns the lowercased string. + * + * @return TeamSpeak3_Helper_String + */ + public function toLower() + { + return new self(strtolower($this->string)); + } + + /** + * Returns the uppercased string. + * + * @return TeamSpeak3_Helper_String + */ + public function toUpper() + { + return new self(strtoupper($this->string)); + } + + /** + * Returns true if the string contains $pattern. + * + * @param string $pattern + * @param boolean $regexp + * @return boolean + */ + public function contains($pattern, $regexp = FALSE) + { + if(empty($pattern)) + { + return TRUE; + } + + if($regexp) + { + return (preg_match("/" . $pattern . "/i", $this->string)) ? TRUE : FALSE; + } + else + { + return (stristr($this->string, $pattern) !== FALSE) ? TRUE : FALSE; + } + } + + /** + * Returns part of a string. + * + * @param integer $start + * @param integer $length + * @return TeamSpeak3_Helper_String + */ + public function substr($start, $length = null) + { + $string = ($length !== null) ? substr($this->string, $start, $length) : substr($this->string, $start); + + return new self($string); + } + + /** + * Splits the string into substrings wherever $separator occurs. + * + * @param string $separator + * @param integer $limit + * @return array + */ + public function split($separator, $limit = 0) + { + $parts = explode($separator, $this->string, ($limit) ? intval($limit) : $this->count()); + + foreach($parts as $key => $val) + { + $parts[$key] = new self($val); + } + + return $parts; + } + + /** + * Appends $part to the string. + * + * @param string $part + * @return TeamSpeak3_Helper_String + */ + public function append($part) + { + $this->string = $this->string . strval($part); + + return $this; + } + + /** + * Prepends $part to the string. + * + * @param string $part + * @return TeamSpeak3_Helper_String + */ + public function prepend($part) + { + $this->string = strval($part) . $this->string; + + return $this; + } + + /** + * Returns a section of the string. + * + * @param string $separator + * @param integer $first + * @param integer $last + * @return TeamSpeak3_Helper_String + */ + public function section($separator, $first = 0, $last = 0) + { + $sections = explode($separator, $this->string); + + $total = count($sections); + $first = intval($first); + $last = intval($last); + + if($first > $total) return null; + if($first > $last) $last = $first; + + for($i = 0; $i < $total; $i++) + { + if($i < $first || $i > $last) + { + unset($sections[$i]); + } + } + + $string = implode($separator, $sections); + + return new self($string); + } + + /** + * Sets the size of the string to $size characters. + * + * @param integer $size + * @param string $char + * @return TeamSpeak3_Helper_String + */ + public function resize($size, $char = "\0") + { + $chars = ($size - $this->count()); + + if($chars < 0) + { + $this->string = substr($this->string, 0, $chars); + } + elseif($chars > 0) + { + $this->string = str_pad($this->string, $size, strval($char)); + } + + return $this; + } + + /** + * Strips whitespaces (or other characters) from the beginning and end of the string. + * + * @return TeamSpeak3_Helper_String + */ + public function trim() + { + $this->string = trim($this->string); + + return $this; + } + + /** + * Escapes a string using the TeamSpeak 3 escape patterns. + * + * @return TeamSpeak3_Helper_String + */ + public function escape() + { + foreach(TeamSpeak3::getEscapePatterns() as $search => $replace) + { + $this->string = str_replace($search, $replace, $this->string); + } + + return $this; + } + + /** + * Unescapes a string using the TeamSpeak 3 escape patterns. + * + * @return TeamSpeak3_Helper_String + */ + public function unescape() + { + $this->string = strtr($this->string, array_flip(TeamSpeak3::getEscapePatterns())); + + return $this; + } + + /** + * Removes any non alphanumeric characters from the string. + * + * @return TeamSpeak3_Helper_String + */ + public function filterAlnum() + { + $this->string = preg_replace("/[^[:alnum:]]/", "", $this->string); + + return $this; + } + + /** + * Removes any non alphabetic characters from the string. + * + * @return TeamSpeak3_Helper_String + */ + public function filterAlpha() + { + $this->string = preg_replace("/[^[:alpha:]]/", "", $this->string); + + return $this; + } + + /** + * Removes any non numeric characters from the string. + * + * @return TeamSpeak3_Helper_String + */ + public function filterDigits() + { + $this->string = preg_replace("/[^[:digit:]]/", "", $this->string); + + return $this; + } + + /** + * Returns TRUE if the string is a numeric value. + * + * @return boolean + */ + public function isInt() + { + return (is_numeric($this->string) && !$this->contains(".")) ? TRUE : FALSE; + } + + /** + * Returns the integer value of the string. + * + * @return float + * @return integer + */ + public function toInt() + { + if($this->string == pow(2, 63) || $this->string == pow(2, 64)) + { + return -1; + } + + return ($this->string > pow(2, 31)) ? floatval($this->string) : intval($this->string); + } + + /** + * Calculates and returns the crc32 polynomial of the string. + * + * @return string + */ + public function toCrc32() + { + return crc32($this->string); + } + + /** + * Calculates and returns the md5 checksum of the string. + * + * @return string + */ + public function toMd5() + { + return md5($this->string); + } + + /** + * Calculates and returns the sha1 checksum of the string. + * + * @return string + */ + public function toSha1() + { + return sha1($this->string); + } + + /** + * Returns TRUE if the string is UTF-8 encoded. This method searches for non-ascii multibyte + * sequences in the UTF-8 range. + * + * @return boolean + */ + public function isUtf8() + { + $pattern = array(); + + $pattern[] = "[\xC2-\xDF][\x80-\xBF]"; // non-overlong 2-byte + $pattern[] = "\xE0[\xA0-\xBF][\x80-\xBF]"; // excluding overlongs + $pattern[] = "[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}"; // straight 3-byte + $pattern[] = "\xED[\x80-\x9F][\x80-\xBF]"; // excluding surrogates + $pattern[] = "\xF0[\x90-\xBF][\x80-\xBF]{2}"; // planes 1-3 + $pattern[] = "[\xF1-\xF3][\x80-\xBF]{3}"; // planes 4-15 + $pattern[] = "\xF4[\x80-\x8F][\x80-\xBF]{2}"; // plane 16 + + return preg_match("%(?:" . implode("|", $pattern) . ")+%xs", $this->string); + } + + /** + * Converts the string to UTF-8. + * + * @return TeamSpeak3_Helper_String + */ + public function toUtf8() + { + if(!$this->isUtf8()) + { + $this->string = utf8_encode($this->string); + } + + return $this; + } + + /** + * Encodes the string with MIME base64 and returns the result. + * + * @return string + */ + public function toBase64() + { + return base64_encode($this->string); + } + + /** + * Decodes the string with MIME base64 and returns the result as an TeamSpeak3_Helper_String + * + * @param string $base64 + * @return TeamSpeak3_Helper_String + */ + public static function fromBase64($base64) + { + return new self(base64_decode($base64)); + } + + /** + * Returns the hexadecimal value of the string. + * + * @return string + */ + public function toHex() + { + $hex = ""; + + foreach($this as $char) + { + $hex .= $char->toHex(); + } + + return $hex; + } + + /** + * Returns the TeamSpeak3_Helper_String based on a given hex value. + * + * @param string $hex + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_String + */ + public static function fromHex($hex) + { + $string = ""; + + if(strlen($hex)%2 == 1) + { + throw new TeamSpeak3_Helper_Exception("given parameter '" . $hex . "' is not a valid hexadecimal number"); + } + + foreach(str_split($hex, 2) as $chunk) + { + $string .= chr(hexdec($chunk)); + } + + return new self($string); + } + + /** + * Returns the string transliterated from UTF-8 to Latin. + * + * @return TeamSpeak3_Helper_String + */ + public function transliterate() + { + $utf8_accents = array( + "à" => "a", + "ô" => "o", + "ď" => "d", + "ḟ" => "f", + "ë" => "e", + "š" => "s", + "ơ" => "o", + "ß" => "ss", + "ă" => "a", + "ř" => "r", + "ț" => "t", + "ň" => "n", + "ā" => "a", + "ķ" => "k", + "ŝ" => "s", + "ỳ" => "y", + "ņ" => "n", + "ĺ" => "l", + "ħ" => "h", + "ṗ" => "p", + "ó" => "o", + "ú" => "u", + "ě" => "e", + "é" => "e", + "ç" => "c", + "ẁ" => "w", + "ċ" => "c", + "õ" => "o", + "ṡ" => "s", + "ø" => "o", + "ģ" => "g", + "ŧ" => "t", + "ș" => "s", + "ė" => "e", + "ĉ" => "c", + "ś" => "s", + "î" => "i", + "ű" => "u", + "ć" => "c", + "ę" => "e", + "ŵ" => "w", + "ṫ" => "t", + "ū" => "u", + "č" => "c", + "ö" => "oe", + "è" => "e", + "ŷ" => "y", + "ą" => "a", + "ł" => "l", + "ų" => "u", + "ů" => "u", + "ş" => "s", + "ğ" => "g", + "ļ" => "l", + "ƒ" => "f", + "ž" => "z", + "ẃ" => "w", + "ḃ" => "b", + "å" => "a", + "ì" => "i", + "ï" => "i", + "ḋ" => "d", + "ť" => "t", + "ŗ" => "r", + "ä" => "ae", + "í" => "i", + "ŕ" => "r", + "ê" => "e", + "ü" => "ue", + "ò" => "o", + "ē" => "e", + "ñ" => "n", + "ń" => "n", + "ĥ" => "h", + "ĝ" => "g", + "đ" => "d", + "ĵ" => "j", + "ÿ" => "y", + "ũ" => "u", + "ŭ" => "u", + "ư" => "u", + "ţ" => "t", + "ý" => "y", + "ő" => "o", + "â" => "a", + "ľ" => "l", + "ẅ" => "w", + "ż" => "z", + "ī" => "i", + "ã" => "a", + "ġ" => "g", + "ṁ" => "m", + "ō" => "o", + "ĩ" => "i", + "ù" => "u", + "į" => "i", + "ź" => "z", + "á" => "a", + "û" => "u", + "þ" => "th", + "ð" => "dh", + "æ" => "ae", + "µ" => "u", + "ĕ" => "e", + "œ" => "oe", + "À" => "A", + "Ô" => "O", + "Ď" => "D", + "Ḟ" => "F", + "Ë" => "E", + "Š" => "S", + "Ơ" => "O", + "Ă" => "A", + "Ř" => "R", + "Ț" => "T", + "Ň" => "N", + "Ā" => "A", + "Ķ" => "K", + "Ŝ" => "S", + "Ỳ" => "Y", + "Ņ" => "N", + "Ĺ" => "L", + "Ħ" => "H", + "Ṗ" => "P", + "Ó" => "O", + "Ú" => "U", + "Ě" => "E", + "É" => "E", + "Ç" => "C", + "Ẁ" => "W", + "Ċ" => "C", + "Õ" => "O", + "Ṡ" => "S", + "Ø" => "O", + "Ģ" => "G", + "Ŧ" => "T", + "Ș" => "S", + "Ė" => "E", + "Ĉ" => "C", + "Ś" => "S", + "Î" => "I", + "Ű" => "U", + "Ć" => "C", + "Ę" => "E", + "Ŵ" => "W", + "Ṫ" => "T", + "Ū" => "U", + "Č" => "C", + "Ö" => "Oe", + "È" => "E", + "Ŷ" => "Y", + "Ą" => "A", + "Ł" => "L", + "Ų" => "U", + "Ů" => "U", + "Ş" => "S", + "Ğ" => "G", + "Ļ" => "L", + "Ƒ" => "F", + "Ž" => "Z", + "Ẃ" => "W", + "Ḃ" => "B", + "Å" => "A", + "Ì" => "I", + "Ï" => "I", + "Ḋ" => "D", + "Ť" => "T", + "Ŗ" => "R", + "Ä" => "Ae", + "Í" => "I", + "Ŕ" => "R", + "Ê" => "E", + "Ü" => "Ue", + "Ò" => "O", + "Ē" => "E", + "Ñ" => "N", + "Ń" => "N", + "Ĥ" => "H", + "Ĝ" => "G", + "Đ" => "D", + "Ĵ" => "J", + "Ÿ" => "Y", + "Ũ" => "U", + "Ŭ" => "U", + "Ư" => "U", + "Ţ" => "T", + "Ý" => "Y", + "Ő" => "O", + "Â" => "A", + "Ľ" => "L", + "Ẅ" => "W", + "Ż" => "Z", + "Ī" => "I", + "Ã" => "A", + "Ġ" => "G", + "Ṁ" => "M", + "Ō" => "O", + "Ĩ" => "I", + "Ù" => "U", + "Į" => "I", + "Ź" => "Z", + "Á" => "A", + "Û" => "U", + "Þ" => "Th", + "Ð" => "Dh", + "Æ" => "Ae", + "Ĕ" => "E", + "Œ" => "Oe", + ); + + return new self($this->toUtf8()->replace(array_keys($utf8_accents), array_values($utf8_accents))); + } + + /** + * Processes the string and replaces all accented UTF-8 characters by unaccented ASCII-7 "equivalents", + * whitespaces are replaced by a pre-defined spacer and the string is lowercase. + * + * @param string $spacer + * @return TeamSpeak3_Helper_String + */ + public function uriSafe($spacer = "-") + { + $this->string = str_replace($spacer, " ", $this->string); + $this->string = $this->transliterate(); + $this->string = preg_replace("/(\s|[^A-Za-z0-9\-])+/", $spacer, trim(strtolower($this->string))); + $this->string = trim($this->string, $spacer); + + return new self($this->string); + } + + /** + * Replaces space characters with percent encoded strings. + * + * @return string + */ + public function spaceToPercent() + { + return str_replace(" ", "%20", $this->string); + } + + /** + * Returns the string as a standard string + * + * @return string + */ + public function toString() + { + return $this->string; + } + + /** + * Magical function that allows you to call PHP's built-in string functions on the TeamSpeak3_Helper_String object. + * + * @param string $function + * @param array $args + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_String + */ + public function __call($function, $args) + { + if(!function_exists($function)) + { + throw new TeamSpeak3_Helper_Exception("cannot call undefined function '" . $function . "' on this object"); + } + + if(count($args)) + { + if(($key = array_search($this, $args, TRUE)) !== FALSE) + { + $args[$key] = $this->string; + } + else + { + throw new TeamSpeak3_Helper_Exception("cannot call undefined function '" . $function . "' without the " . __CLASS__ . " object parameter"); + } + + $return = call_user_func_array($function, $args); + } + else + { + $return = call_user_func($function, $this->string); + } + + if(is_string($return)) + { + $this->string = $return; + } + else + { + return $return; + } + + return $this; + } + + /** + * Returns the character as a standard string. + * + * @return string + */ + public function __toString() + { + return (string) $this->string; + } + + /** + * @ignore + */ + public function count() + { + return strlen($this->string); + } + + /** + * @ignore + */ + public function rewind() + { + $this->position = 0; + } + + /** + * @ignore + */ + public function valid() + { + return $this->position < $this->count(); + } + + /** + * @ignore + */ + public function key() + { + return $this->position; + } + + /** + * @ignore + */ + public function current() + { + return new TeamSpeak3_Helper_Char($this->string{$this->position}); + } + + /** + * @ignore + */ + public function next() + { + $this->position++; + } + + /** + * @ignore + */ + public function offsetExists($offset) + { + return ($offset < strlen($this->string)) ? TRUE : FALSE; + } + + /** + * @ignore + */ + public function offsetGet($offset) + { + return ($this->offsetExists($offset)) ? new TeamSpeak3_Helper_Char($this->string{$offset}) : null; + } + + /** + * @ignore + */ + public function offsetSet($offset, $value) + { + if(!$this->offsetExists($offset)) return; + + $this->string{$offset} = strval($value); + } + + /** + * @ignore + */ + public function offsetUnset($offset) + { + if(!$this->offsetExists($offset)) return; + + $this->string = substr_replace($this->string, "", $offset, 1); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Uri.php b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Uri.php new file mode 100644 index 0000000..4e89930 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Helper/Uri.php @@ -0,0 +1,717 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Uri + * @brief Helper class for URI handling. + */ +class TeamSpeak3_Helper_Uri +{ + /** + * Stores the URI scheme. + * + * @var string + */ + protected $scheme = null; + + /** + * Stores the URI username + * + * @var string + */ + protected $user = null; + + /** + * Stores the URI password. + * + * @var string + */ + protected $pass = null; + + /** + * Stores the URI host. + * + * @var string + */ + protected $host = null; + + /** + * Stores the URI port. + * + * @var string + */ + protected $port = null; + + /** + * Stores the URI path. + * + * @var string + */ + protected $path = null; + + /** + * Stores the URI query string. + * + * @var string + */ + protected $query = null; + + /** + * Stores the URI fragment string. + * + * @var string + */ + protected $fragment = null; + + /** + * Stores grammar rules for validation via regex. + * + * @var array + */ + protected $regex = array(); + + /** + * The TeamSpeak3_Helper_Uri constructor. + * + * @param string $uri + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_Uri + */ + public function __construct($uri) + { + $uri = explode(":", strval($uri), 2); + + $this->scheme = strtolower($uri[0]); + $uriString = isset($uri[1]) ? $uri[1] : ""; + + if(!ctype_alnum($this->scheme)) + { + throw new TeamSpeak3_Helper_Exception("invalid URI scheme '" . $this->scheme . "' supplied"); + } + + /* grammar rules for validation */ + $this->regex["alphanum"] = "[^\W_]"; + $this->regex["escaped"] = "(?:%[\da-fA-F]{2})"; + $this->regex["mark"] = "[-_.!~*'()\[\]]"; + $this->regex["reserved"] = "[;\/?:@&=+$,]"; + $this->regex["unreserved"] = "(?:" . $this->regex["alphanum"] . "|" . $this->regex["mark"] . ")"; + $this->regex["segment"] = "(?:(?:" . $this->regex["unreserved"] . "|" . $this->regex["escaped"] . "|[:@&=+$,;])*)"; + $this->regex["path"] = "(?:\/" . $this->regex["segment"] . "?)+"; + $this->regex["uric"] = "(?:" . $this->regex["reserved"] . "|" . $this->regex["unreserved"] . "|" . $this->regex["escaped"] . ")"; + + if(strlen($uriString) > 0) + { + $this->parseUri($uriString); + } + + if(!$this->isValid()) + { + throw new TeamSpeak3_Helper_Exception("invalid URI supplied"); + } + } + + /** + * Parses the scheme-specific portion of the URI and place its parts into instance variables. + * + * @throws TeamSpeak3_Helper_Exception + * @return void + */ + protected function parseUri($uriString = '') + { + $status = @preg_match("~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~", $uriString, $matches); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI scheme-specific decomposition failed"); + } + + if(!$status) return; + + $this->path = (isset($matches[4])) ? $matches[4] : ''; + $this->query = (isset($matches[6])) ? $matches[6] : ''; + $this->fragment = (isset($matches[8])) ? $matches[8] : ''; + + $status = @preg_match("~^(([^:@]*)(:([^@]*))?@)?((?(?=[[])[[][^]]+[]]|[^:]+))(:(.*))?$~", (isset($matches[3])) ? $matches[3] : "", $matches); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI scheme-specific authority decomposition failed"); + } + + if(!$status) return; + + $this->user = isset($matches[2]) ? $matches[2] : ""; + $this->pass = isset($matches[4]) ? $matches[4] : ""; + $this->host = isset($matches[5]) === TRUE ? preg_replace('~^\[([^]]+)\]$~', '\1', $matches[5]) : ""; + $this->port = isset($matches[7]) ? $matches[7] : ""; + } + + /** + * Validate the current URI from the instance variables. + * + * @return boolean + */ + public function isValid() + { + return ($this->checkUser() && $this->checkPass() && $this->checkHost() && $this->checkPort() && $this->checkPath() && $this->checkQuery() && $this->checkFragment()); + } + + /** + * Returns TRUE if a given URI is valid. + * + * @param string $uri + * @return boolean + */ + public static function check($uri) + { + try + { + $uri = new self(strval($uri)); + } + catch(Exception $e) + { + return FALSE; + } + + return $uri->valid(); + } + + /** + * Returns TRUE if the URI has a scheme. + * + * @return boolean + */ + public function hasScheme() + { + return strlen($this->scheme) ? TRUE : FALSE; + } + + /** + * Returns the scheme. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getScheme($default = null) + { + return ($this->hasScheme()) ? new TeamSpeak3_Helper_String($this->scheme) : $default; + } + + /** + * Returns TRUE if the username is valid. + * + * @param string $username + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkUser($username = null) + { + if($username === null) + { + $username = $this->user; + } + + if(strlen($username) == 0) + { + return TRUE; + } + + $pattern = "/^(" . $this->regex["alphanum"] . "|" . $this->regex["mark"] . "|" . $this->regex["escaped"] . "|[;:&=+$,])+$/"; + $status = @preg_match($pattern, $username); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI username validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a username. + * + * @return boolean + */ + public function hasUser() + { + return strlen($this->user) ? TRUE : FALSE; + } + + /** + * Returns the username. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getUser($default = null) + { + return ($this->hasUser()) ? new TeamSpeak3_Helper_String($this->user) : $default; + } + + /** + * Returns TRUE if the password is valid. + * + * @param string $password + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkPass($password = null) + { + if($password === null) { + $password = $this->pass; + } + + if(strlen($password) == 0) + { + return TRUE; + } + + $pattern = "/^(" . $this->regex["alphanum"] . "|" . $this->regex["mark"] . "|" . $this->regex["escaped"] . "|[;:&=+$,])+$/"; + $status = @preg_match($pattern, $password); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI password validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a password. + * + * @return boolean + */ + public function hasPass() + { + return strlen($this->pass) ? TRUE : FALSE; + } + + /** + * Returns the password. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getPass($default = null) + { + return ($this->hasPass()) ? new TeamSpeak3_Helper_String($this->pass) : $default; + } + + /** + * Returns TRUE if the host is valid. + * + * @param string $host + * @return boolean + */ + public function checkHost($host = null) + { + if($host === null) + { + $host = $this->host; + } + + return TRUE; + } + + /** + * Returns TRUE if the URI has a host. + * + * @return boolean + */ + public function hasHost() + { + return strlen($this->host) ? TRUE : FALSE; + } + + /** + * Returns the host. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getHost($default = null) + { + return ($this->hasHost()) ? new TeamSpeak3_Helper_String($this->host) : $default; + } + + /** + * Returns TRUE if the port is valid. + * + * @param integer $port + * @return boolean + */ + public function checkPort($port = null) + { + if($port === null) + { + $port = $this->port; + } + + return TRUE; + } + + /** + * Returns TRUE if the URI has a port. + * + * @return boolean + */ + public function hasPort() + { + return strlen($this->port) ? TRUE : FALSE; + } + + /** + * Returns the port. + * + * @param mixed default + * @return integer + */ + public function getPort($default = null) + { + return ($this->hasPort()) ? intval($this->port) : $default; + } + + /** + * Returns TRUE if the path is valid. + * + * @param string $path + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkPath($path = null) + { + if($path === null) + { + $path = $this->path; + } + + if(strlen($path) == 0) + { + return TRUE; + } + + $pattern = "/^" . $this->regex["path"] . "$/"; + $status = @preg_match($pattern, $path); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI path validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a path. + * + * @return boolean + */ + public function hasPath() + { + return strlen($this->path) ? TRUE : FALSE; + } + + /** + * Returns the path. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getPath($default = null) + { + return ($this->hasPath()) ? new TeamSpeak3_Helper_String($this->path) : $default; + } + + /** + * Returns TRUE if the query string is valid. + * + * @param string $query + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkQuery($query = null) + { + if($query === null) + { + $query = $this->query; + } + + if(strlen($query) == 0) + { + return TRUE; + } + + $pattern = "/^" . $this->regex["uric"] . "*$/"; + $status = @preg_match($pattern, $query); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI query string validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a query string. + * + * @return boolean + */ + public function hasQuery() + { + return strlen($this->query) ? TRUE : FALSE; + } + + /** + * Returns an array containing the query string elements. + * + * @param mixed $default + * @return array + */ + public function getQuery($default = array()) + { + if(!$this->hasQuery()) + { + return $default; + } + + parse_str($this->query, $queryArray); + + return $queryArray; + } + + /** + * Returns TRUE if the URI has a query variable. + * + * @return boolean + */ + public function hasQueryVar($key) + { + if(!$this->hasQuery()) return FALSE; + + parse_str($this->query, $queryArray); + + return array_key_exists($key, $queryArray) ? TRUE : FALSE; + } + + /** + * Returns a single variable from the query string. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public function getQueryVar($key, $default = null) + { + if(!$this->hasQuery()) return $default; + + parse_str($this->query, $queryArray); + + if(array_key_exists($key, $queryArray)) + { + $val = $queryArray[$key]; + + if(ctype_digit($val)) + { + return intval($val); + } + elseif(is_string($val)) + { + return new TeamSpeak3_Helper_String($val); + } + else + { + return $val; + } + } + + return $default; + } + + /** + * Returns TRUE if the fragment string is valid. + * + * @param string $fragment + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkFragment($fragment = null) + { + if($fragment === null) + { + $fragment = $this->fragment; + } + + if(strlen($fragment) == 0) + { + return TRUE; + } + + $pattern = "/^" . $this->regex["uric"] . "*$/"; + $status = @preg_match($pattern, $fragment); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI fragment validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a fragment string. + * + * @return boolean + */ + public function hasFragment() + { + return strlen($this->fragment) ? TRUE : FALSE; + } + + /** + * Returns the fragment. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getFragment($default = null) + { + return ($this->hasFragment()) ? new TeamSpeak3_Helper_String($this->fragment) : $default; + } + + /** + * Returns a specified instance parameter from the $_REQUEST array. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function getUserParam($key, $default = null) + { + return (array_key_exists($key, $_REQUEST) && !empty($_REQUEST[$key])) ? self::stripslashesRecursive($_REQUEST[$key]) : $default; + } + + /** + * Returns a specified environment parameter from the $_SERVER array. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function getHostParam($key, $default = null) + { + return (array_key_exists($key, $_SERVER) && !empty($_SERVER[$key])) ? $_SERVER[$key] : $default; + } + + /** + * Returns a specified session parameter from the $_SESSION array. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function getSessParam($key, $default = null) + { + return (array_key_exists($key, $_SESSION) && !empty($_SESSION[$key])) ? $_SESSION[$key] : $default; + } + + /** + * Returns an array containing the three main parts of a FQDN (Fully Qualified Domain Name), including the + * top-level domain, the second-level domains or hostname and the third-level domain. + * + * @param string $hostname + * @return array + */ + public static function getFQDNParts($hostname) + { + if(!preg_match("/^([a-z0-9][a-z0-9-]{0,62}\.)*([a-z0-9][a-z0-9-]{0,62}\.)+([a-z]{2,6})$/i", $hostname, $matches)) + { + return array(); + } + + $parts["tld"] = $matches[3]; + $parts["2nd"] = $matches[2]; + $parts["3rd"] = $matches[1]; + + return $parts; + } + + /** + * Returns the applications host address. + * + * @return TeamSpeak3_Helper_String + */ + public static function getHostUri() + { + $sheme = (self::getHostParam("HTTPS") == "on") ? "https" : "http"; + + $serverName = new TeamSpeak3_Helper_String(self::getHostParam("HTTP_HOST")); + $serverPort = self::getHostParam("SERVER_PORT"); + $serverPort = ($serverPort != 80 && $serverPort != 443) ? ":" . $serverPort : ""; + + if($serverName->endsWith($serverPort)) + { + $serverName = $serverName->replace($serverPort, ""); + } + + return new TeamSpeak3_Helper_String($sheme . "://" . $serverName . $serverPort); + } + + /** + * Returns the applications base address. + * + * @return string + */ + public static function getBaseUri() + { + $scriptPath = new TeamSpeak3_Helper_String(dirname(self::getHostParam("SCRIPT_NAME"))); + + return self::getHostUri()->append(($scriptPath == DIRECTORY_SEPARATOR ? "" : $scriptPath) . "/"); + } + + /** + * Strips slashes from each element of an array using stripslashes(). + * + * @param mixed $var + * @return mixed + */ + protected static function stripslashesRecursive($var) + { + if(!is_array($var)) + { + return stripslashes(strval($var)); + } + + foreach($var as $key => $val) + { + $var[$key] = (is_array($val)) ? stripslashesRecursive($val) : stripslashes(strval($val)); + } + + return $var; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Node/Abstract.php b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Abstract.php new file mode 100644 index 0000000..d6244f8 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Abstract.php @@ -0,0 +1,624 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Abstract + * @brief Abstract class describing a TeamSpeak 3 node and all it's parameters. + */ +abstract class TeamSpeak3_Node_Abstract implements RecursiveIterator, ArrayAccess, Countable +{ + /** + * @ignore + */ + protected $parent = null; + + /** + * @ignore + */ + protected $server = null; + + /** + * @ignore + */ + protected $nodeId = 0x00; + + /** + * @ignore + */ + protected $nodeList = null; + + /** + * @ignore + */ + protected $nodeInfo = array(); + + /** + * @ignore + */ + protected $storage = array(); + + /** + * Sends a prepared command to the server and returns the result. + * + * @param string $cmd + * @param boolean $throw + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function request($cmd, $throw = TRUE) + { + return $this->getParent()->request($cmd, $throw); + } + + /** + * Uses given parameters and returns a prepared ServerQuery command. + * + * @param string $cmd + * @param array $params + * @return TeamSpeak3_Helper_String + */ + public function prepare($cmd, array $params = array()) + { + return $this->getParent()->prepare($cmd, $params); + } + + /** + * Prepares and executes a ServerQuery command and returns the result. + * + * @param string $cmd + * @param array $params + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function execute($cmd, array $params = array()) + { + return $this->request($this->prepare($cmd, $params)); + } + + /** + * Returns the parent object of the current node. + * + * @return TeamSpeak3_Adapter_ServerQuery + * @return TeamSpeak3_Node_Abstract + */ + public function getParent() + { + return $this->parent; + } + + /** + * Returns the primary ID of the current node. + * + * @return integer + */ + public function getId() + { + return $this->nodeId; + } + + /** + * Returns TRUE if the node icon has a local source. + * + * @param string $key + * @return boolean + */ + public function iconIsLocal($key) + { + return ($this[$key] > 0 && $this[$key] < 1000) ? TRUE : FALSE; + } + + /** + * Returns the internal path of the node icon. + * + * @param string $key + * @return TeamSpeak3_Helper_String + */ + public function iconGetName($key) + { + $iconid = ($this[$key] < 0) ? (pow(2, 32))-($this[$key]*-1) : $this[$key]; + + return new TeamSpeak3_Helper_String("/icon_" . $iconid); + } + + /** + * Returns a possible classname for the node which can be used as a HTML property. + * + * @param string $prefix + * @return string + */ + public function getClass($prefix = "ts3_") + { + if($this instanceof TeamSpeak3_Node_Channel && $this->isSpacer()) + { + return $prefix . "spacer"; + } + elseif($this instanceof TeamSpeak3_Node_Client && $this["client_type"]) + { + return $prefix . "query"; + } + + return $prefix . TeamSpeak3_Helper_String::factory(get_class($this))->section("_", 2)->toLower(); + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + abstract public function getUniqueId(); + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + abstract public function getIcon(); + + /** + * Returns a symbol representing the node. + * + * @return string + */ + abstract public function getSymbol(); + + /** + * Returns the HTML code to display a TeamSpeak 3 viewer. + * + * @param TeamSpeak3_Viewer_Interface $viewer + * @return string + */ + public function getViewer(TeamSpeak3_Viewer_Interface $viewer) + { + $html = $viewer->fetchObject($this); + + $iterator = new RecursiveIteratorIterator($this, RecursiveIteratorIterator::SELF_FIRST); + + foreach($iterator as $node) + { + $siblings = array(); + + for($level = 0; $level < $iterator->getDepth(); $level++) + { + $siblings[] = ($iterator->getSubIterator($level)->hasNext()) ? 1 : 0; + } + + $siblings[] = (!$iterator->getSubIterator($level)->hasNext()) ? 1 : 0; + + $html .= $viewer->fetchObject($node, $siblings); + } + + return $html; + } + + /** + * Filters given node list array using specified filter rules. + * + * @param array $nodes + * @param array $rules + * @return array + */ + protected function filterList(array $nodes = array(), array $rules = array()) + { + if(!empty($rules)) + { + foreach($nodes as $node) + { + if(!$node instanceof TeamSpeak3_Node_Abstract) continue; + + $props = $node->getInfo(FALSE); + $props = array_intersect_key($props, $rules); + + foreach($props as $key => $val) + { + if($val instanceof TeamSpeak3_Helper_String) + { + $match = $val->contains($rules[$key], TRUE); + } + else + { + $match = $val == $rules[$key]; + } + + if($match === FALSE) + { + unset($nodes[$node->getId()]); + } + } + } + } + + return $nodes; + } + + /** + * Returns all information available on this node. If $convert is enabled, some property + * values will be converted to human-readable values. + * + * @param boolean $extend + * @param boolean $convert + * @return array + */ + public function getInfo($extend = TRUE, $convert = FALSE) + { + if($extend) + { + $this->fetchNodeInfo(); + } + + if($convert) + { + $info = $this->nodeInfo; + + foreach($info as $key => $val) + { + $key = TeamSpeak3_Helper_String::factory($key); + + if($key->contains("_bytes_")) + { + $info[$key->toString()] = TeamSpeak3_Helper_Convert::bytes($val); + } + elseif($key->contains("_bandwidth_")) + { + $info[$key->toString()] = TeamSpeak3_Helper_Convert::bytes($val) . "/s"; + } + elseif($key->contains("_packets_")) + { + $info[$key->toString()] = number_format($val, null, null, "."); + } + elseif($key->contains("_packetloss_")) + { + $info[$key->toString()] = sprintf("%01.2f", floatval($val->toString())*100) . "%"; + } + elseif($key->endsWith("_uptime")) + { + $info[$key->toString()] = TeamSpeak3_Helper_Convert::seconds($val); + } + elseif($key->endsWith("_version")) + { + $info[$key->toString()] = TeamSpeak3_Helper_Convert::version($val); + } + elseif($key->endsWith("_icon_id")) + { + $info[$key->toString()] = $this->iconGetName($key)->filterDigits(); + } + } + + return $info; + } + + return $this->nodeInfo; + } + + /** + * Returns the specified property or a pre-defined default value from the node info array. + * + * @param string $property + * @param mixed $default + * @return mixed + */ + public function getProperty($property, $default = null) + { + if(!$this->offsetExists($property)) + { + $this->fetchNodeInfo(); + } + + if(!$this->offsetExists($property)) + { + return $default; + } + + return $this->nodeInfo[(string) $property]; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return get_class($this); + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function toString() + { + return $this->__toString(); + } + + /** + * Returns an assoc array filled with current node info properties. + * + * @return array + */ + public function toArray() + { + return $this->nodeList; + } + + /** + * Called whenever we're using an unknown method. + * + * @param string $name + * @param array $args + * @throws TeamSpeak3_Node_Exception + * @return mixed + */ + public function __call($name, array $args) + { + if($this->getParent() instanceof TeamSpeak3_Node_Abstract) + { + return call_user_func_array(array($this->getParent(), $name), $args); + } + + throw new TeamSpeak3_Node_Exception("node method '" . $name . "()' does not exist"); + } + + /** + * Writes data to the internal storage array. + * + * @param string $key + * @param mixed $val + * @return void + */ + protected function setStorage($key, $val) + { + $this->storage[$key] = $val; + } + + /** + * Returns data from the internal storage array. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + protected function getStorage($key, $default = null) + { + return !empty($this->storage[$key]) ? $this->storage[$key] : $default; + } + + /** + * Deletes data from the internal storage array. + * + * @param string $key + * @return void + */ + protected function delStorage($key) + { + unset($this->storage[$key]); + } + + /** + * Commit pending data. + * + * @return array + */ + public function __sleep() + { + return array("parent", "storage", "nodeId"); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + } + + /** + * @ignore + */ + protected function fetchNodeInfo() + { + return; + } + + /** + * @ignore + */ + protected function resetNodeInfo() + { + $this->nodeInfo = array(); + } + + /** + * @ignore + */ + protected function verifyNodeList() + { + if($this->nodeList === null) + { + $this->fetchNodeList(); + } + } + + /** + * @ignore + */ + protected function resetNodeList() + { + $this->nodeList = null; + } + + /** + * @ignore + */ + public function count() + { + $this->verifyNodeList(); + + return count($this->nodeList); + } + + /** + * @ignore + */ + public function current() + { + $this->verifyNodeList(); + + return current($this->nodeList); + } + + /** + * @ignore + */ + public function getChildren() + { + $this->verifyNodeList(); + + return $this->current(); + } + + /** + * @ignore + */ + public function hasChildren() + { + $this->verifyNodeList(); + + return $this->current()->count() > 0; + } + + /** + * @ignore + */ + public function hasNext() + { + $this->verifyNodeList(); + + return $this->key()+1 < $this->count(); + } + + /** + * @ignore + */ + public function key() + { + $this->verifyNodeList(); + + return key($this->nodeList); + } + + /** + * @ignore + */ + public function valid() + { + $this->verifyNodeList(); + + return $this->key() !== null; + } + + /** + * @ignore + */ + public function next() + { + $this->verifyNodeList(); + + return next($this->nodeList); + } + + /** + * @ignore + */ + public function rewind() + { + $this->verifyNodeList(); + + return reset($this->nodeList); + } + + /** + * @ignore + */ + public function offsetExists($offset) + { + return array_key_exists((string) $offset, $this->nodeInfo) ? TRUE : FALSE; + } + + /** + * @ignore + */ + public function offsetGet($offset) + { + if(!$this->offsetExists($offset)) + { + $this->fetchNodeInfo(); + } + + if(!$this->offsetExists($offset)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + return $this->nodeInfo[(string) $offset]; + } + + /** + * @ignore + */ + public function offsetSet($offset, $value) + { + if(method_exists($this, "modify")) + { + return $this->modify(array((string) $offset => $value)); + } + + throw new TeamSpeak3_Node_Exception("node '" . get_class($this) . "' is read only"); + } + + /** + * @ignore + */ + public function offsetUnset($offset) + { + unset($this->nodeInfo[(string) $offset]); + } + + /** + * @ignore + */ + public function __get($offset) + { + return $this->offsetGet($offset); + } + + /** + * @ignore + */ + public function __set($offset, $value) + { + $this->offsetSet($offset, $value); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Node/Channel.php b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Channel.php new file mode 100644 index 0000000..cbc1835 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Channel.php @@ -0,0 +1,588 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Channel + * @brief Class describing a TeamSpeak 3 channel and all it's parameters. + */ +class TeamSpeak3_Node_Channel extends TeamSpeak3_Node_Abstract +{ + /** + * The TeamSpeak3_Node_Channel constructor. + * + * @param TeamSpeak3_Node_Server $server + * @param array $info + * @param string $index + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function __construct(TeamSpeak3_Node_Server $server, array $info, $index = "cid") + { + $this->parent = $server; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Returns an array filled with TeamSpeak3_Node_Channel objects. + * + * @param array $filter + * @return array + */ + public function subChannelList(array $filter = array()) + { + $channels = array(); + + foreach($this->getParent()->channelList() as $channel) + { + if($channel["pid"] == $this->getId()) + { + $channels[$channel->getId()] = $channel; + } + } + + return $this->filterList($channels, $filter); + } + + /** + * Returns the TeamSpeak3_Node_Channel object matching the given ID. + * + * @param integer $cid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function subChannelGetById($cid) + { + if(!array_key_exists((string) $cid, $this->subChannelList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + return $this->channelList[(string) $cid]; + } + + /** + * Returns the TeamSpeak3_Node_Channel object matching the given name. + * + * @param integer $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function subChannelGetByName($name) + { + foreach($this->subChannelList() as $channel) + { + if($channel["channel_name"] == $name) return $channel; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + /** + * Returns an array filled with TeamSpeak3_Node_Client objects. + * + * @param array $filter + * @return array + */ + public function clientList(array $filter = array()) + { + $clients = array(); + + foreach($this->getParent()->clientList() as $client) + { + if($client["cid"] == $this->getId()) + { + $clients[$client->getId()] = $client; + } + } + + return $this->filterList($clients, $filter); + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given ID. + * + * @param integer $clid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetById($clid) + { + if(!array_key_exists($clid, $this->clientList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + return $this->clientList[intval($clid)]; + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given name. + * + * @param integer $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetByName($name) + { + foreach($this->clientList() as $client) + { + if($client["client_nickname"] == $name) return $client; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + /** + * Returns a list of permissions defined for a client in the channel. + * + * @param integer $cldbid + * @param boolean $permsid + * @return array + */ + public function clientPermList($cldbid, $permsid = FALSE) + { + return $this->getParent()->channelClientPermList($this->getId(), $cldbid, $permsid); + } + + /** + * Adds a set of specified permissions to a client in a specific channel. Multiple permissions can be added by + * providing the two parameters of each permission. + * + * @param integer $cldbid + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function clientPermAssign($cldbid, $permid, $permvalue) + { + $this->getParent()->channelClientPermAssign($this->getId(), $cldbid, $permid, $permvalue); + } + + /** + * Alias for clientPermAssign(). + * + * @deprecated + */ + public function clientPermAssignByName($cldbid, $permname, $permvalue) + { + $this->clientPermAssign($cldbid, $permname, $permvalue); + } + + /** + * Removes a set of specified permissions from a client in the channel. Multiple permissions can be removed at once. + * + * @param integer $cldbid + * @param integer $permid + * @return void + */ + public function clientPermRemove($cldbid, $permid) + { + $this->getParent()->channelClientPermRemove($this->getId(), $cldbid, $permid); + } + + /** + * Alias for clientPermRemove(). + * + * @deprecated + */ + public function clientPermRemoveByName($cldbid, $permname) + { + $this->clientPermRemove($cldbid, $permname); + } + + /** + * Returns a list of permissions defined for the channel. + * + * @param boolean $permsid + * @return array + */ + public function permList($permsid = FALSE) + { + return $this->getParent()->channelPermList($this->getId(), $permsid); + } + + /** + * Adds a set of specified permissions to the channel. Multiple permissions can be added by + * providing the two parameters of each permission. + * + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function permAssign($permid, $permvalue) + { + $this->getParent()->channelPermAssign($this->getId(), $permid, $permvalue); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permAssignByName($permname, $permvalue) + { + $this->permAssign($permname, $permvalue); + } + + /** + * Removes a set of specified permissions from the channel. Multiple permissions can be removed at once. + * + * @param integer $permid + * @return void + */ + public function permRemove($permid) + { + $this->getParent()->channelPermRemove($this->getId(), $permid); + } + + /** + * Alias for permRemove(). + * + * @deprecated + */ + public function permRemoveByName($permname) + { + $this->permRemove($permname); + } + + /** + * Returns a list of files and directories stored in the channels file repository. + * + * @param string $cpw + * @param string $path + * @param boolean $recursive + * @return array + */ + public function fileList($cpw = "", $path = "/", $recursive = FALSE) + { + return $this->getParent()->channelFileList($this->getId(), $cpw, $path, $recursive); + } + + /** + * Returns detailed information about the specified file stored in the channels file repository. + * + * @param string $cpw + * @param string $name + * @return array + */ + public function fileInfo($cpw = "", $name = "/") + { + return $this->getParent()->channelFileInfo($this->getId(), $cpw, $name); + } + + /** + * Renames a file in the channels file repository. If the two parameters $tcid and $tcpw are specified, the file + * will be moved into another channels file repository. + * + * @param string $cpw + * @param string $oldname + * @param string $newname + * @param integer $tcid + * @param string $tcpw + * @return void + */ + public function fileRename($cpw = "", $oldname = "/", $newname = "/", $tcid = null, $tcpw = null) + { + $this->getParent()->channelFileRename($this->getId(), $cpw, $oldname, $newname, $tcid, $tcpw); + } + + /** + * Deletes one or more files stored in the channels file repository. + * + * @param string $cpw + * @param string $path + * @return void + */ + public function fileDelete($cpw = "", $name = "/") + { + $this->getParent()->channelFileDelete($this->getId(), $cpw, $name); + } + + /** + * Creates new directory in a channels file repository. + * + * @param string $cpw + * @param string $dirname + * @return void + */ + public function dirCreate($cpw = "", $dirname = "/") + { + $this->getParent()->channelDirCreate($this->getId(), $cpw, $dirname); + } + + /** + * Returns the level of the channel. + * + * @return integer + */ + public function getLevel() + { + return $this->getParent()->channelGetLevel($this->getId()); + } + + /** + * Returns the pathway of the channel which can be used as a clients default channel. + * + * @return string + */ + public function getPathway() + { + return $this->getParent()->channelGetPathway($this->getId()); + } + + /** + * Returns the possible spacer type of the channel. + * + * @return integer + */ + public function spacerGetType() + { + return $this->getParent()->channelSpacerGetType($this->getId()); + } + + /** + * Returns the possible spacer alignment of the channel. + * + * @return integer + */ + public function spacerGetAlign() + { + return $this->getParent()->channelSpacerGetAlign($this->getId()); + } + + /** + * Returns TRUE if the channel is a spacer. + * + * @return boolean + */ + public function isSpacer() + { + return $this->getParent()->channelIsSpacer($this); + } + + /** + * Downloads and returns the channels icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("channel_icon_id") || $this["channel_icon_id"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("channel_icon_id")); + $transfer = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * Changes the channel configuration using given properties. + * + * @param array $properties + * @return void + */ + public function modify(array $properties) + { + $properties["cid"] = $this->getId(); + + $this->execute("channeledit", $properties); + $this->resetNodeInfo(); + } + + /** + * Sends a text message to all clients in the channel. + * + * @param string $msg + * @param string $cpw + * @return void + */ + public function message($msg, $cpw = null) + { + if($this->getId() != $this->getParent()->whoamiGet("client_channel_id")) + { + $this->getParent()->clientMove($this->getParent()->whoamiGet("client_id"), $this->getId(), $cpw); + } + + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $this->getId(), "targetmode" => TeamSpeak3::TEXTMSG_CHANNEL)); + } + + /** + * Deletes the channel. + * + * @param boolean $force + * @return void + */ + public function delete($force = FALSE) + { + $this->getParent()->channelDelete($this->getId(), $force); + + unset($this); + } + + /** + * Moves the channel to the parent channel specified with $pid. + * + * @param integer $pid + * @param integer $order + * @return void + */ + public function move($pid, $order = null) + { + $this->getParent()->channelMove($this->getId(), $pid, $order); + } + + /** + * Sends a plugin command to all clients in the channel. + * + * @param string $plugin + * @param string $data + * @param string $cpw + * @param boolean $subscribed + * @return void + */ + public function sendPluginCmd($plugin, $data, $cpw = null, $subscribed = FALSE) + { + if($this->getId() != $this->getParent()->whoamiGet("client_channel_id")) + { + $this->getParent()->clientMove($this->getParent()->whoamiGet("client_id"), $this->getId(), $cpw); + } + + $this->execute("plugincmd", array("name" => $plugin, "data" => $data, "targetmode" => $subscribed ? TeamSpeak3::PLUGINCMD_CHANNEL_SUBSCRIBED : TeamSpeak3::PLUGINCMD_CHANNEL)); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + + if($this->getParent()->getLoadClientlistFirst()) + { + foreach($this->clientList() as $client) + { + if($client["cid"] == $this->getId()) + { + $this->nodeList[] = $client; + } + } + + foreach($this->subChannelList() as $channel) + { + if($channel["pid"] == $this->getId()) + { + $this->nodeList[] = $channel; + } + } + } + else + { + foreach($this->subChannelList() as $channel) + { + if($channel["pid"] == $this->getId()) + { + $this->nodeList[] = $channel; + } + } + + foreach($this->clientList() as $client) + { + if($client["cid"] == $this->getId()) + { + $this->nodeList[] = $client; + } + } + } + } + + /** + * @ignore + */ + protected function fetchNodeInfo() + { + $this->nodeInfo = array_merge($this->nodeInfo, $this->execute("channelinfo", array("cid" => $this->getId()))->toList()); + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_ch" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + if($this["channel_maxclients"] != -1 && $this["channel_maxclients"] <= $this["total_clients"]) + { + return "channel_full"; + } + elseif($this["channel_flag_password"]) + { + return "channel_pass"; + } + else + { + return "channel_open"; + } + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "#"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["channel_name"]; + } +} + diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Node/Channelgroup.php b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Channelgroup.php new file mode 100644 index 0000000..dadc70f --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Channelgroup.php @@ -0,0 +1,276 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Channelgroup + * @brief Class describing a TeamSpeak 3 channel group and all it's parameters. + */ +class TeamSpeak3_Node_Channelgroup extends TeamSpeak3_Node_Abstract +{ + /** + * The TeamSpeak3_Node_Channelgroup constructor. + * + * @param TeamSpeak3_Node_Server $server + * @param array $info + * @param string $index + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channelgroup + */ + public function __construct(TeamSpeak3_Node_Server $server, array $info, $index = "cgid") + { + $this->parent = $server; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Renames the channel group specified. + * + * @param string $name + * @return void + */ + public function rename($name) + { + $this->getParent()->channelGroupRename($this->getId(), $name); + } + + /** + * Deletes the channel group. If $force is set to TRUE, the channel group will be + * deleted even if there are clients within. + * + * @param boolean $force + * @return void + */ + public function delete($force = FALSE) + { + $this->getParent()->channelGroupDelete($this->getId(), $force); + + unset($this); + } + + /** + * Creates a copy of the channel group and returns the new groups ID. + * + * @param string $name + * @param integer $tcgid + * @param integer $type + * @return integer + */ + public function copy($name = null, $tcgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + return $this->getParent()->channelGroupCopy($this->getId(), $name, $tcgid, $type); + } + + /** + * Returns a list of permissions assigned to the channel group. + * + * @param boolean $permsid + * @return array + */ + public function permList($permsid = FALSE) + { + return $this->getParent()->channelGroupPermList($this->getId(), $permsid); + } + + /** + * Adds a set of specified permissions to the channel group. Multiple permissions + * can be added by providing the two parameters of each permission in separate arrays. + * + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function permAssign($permid, $permvalue) + { + $this->getParent()->channelGroupPermAssign($this->getId(), $permid, $permvalue); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permAssignByName($permname, $permvalue) + { + $this->permAssign($permname, $permvalue); + } + + /** + * Removes a set of specified permissions from the channel group. Multiple + * permissions can be removed at once. + * + * @param integer $permid + * @return void + */ + public function permRemove($permid) + { + $this->getParent()->channelGroupPermRemove($this->getId(), $permid); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permRemoveByName($permname) + { + $this->permRemove($permname); + } + + /** + * Returns a list of clients assigned to the server group specified. + * + * @return array + */ + public function clientList() + { + return $this->getParent()->channelGroupClientList($this->getId()); + } + + /** + * Alias for privilegeKeyCreate(). + * + * @deprecated + */ + public function tokenCreate($cid, $description = null, $customset = null) + { + return $this->privilegeKeyCreate($cid, $description, $customset); + } + + /** + * Creates a new privilege key (token) for the channel group and returns the key. + * + * @param integer $cid + * @param string $description + * @param string $customset + * @return TeamSpeak3_Helper_String + */ + public function privilegeKeyCreate($cid, $description = null, $customset = null) + { + return $this->getParent()->privilegeKeyCreate(TeamSpeak3::TOKEN_CHANNELGROUP, $this->getId(), $cid, $description, $customset); + } + + /** + * Sends a text message to all clients residing in the channel group on the virtual server. + * + * @param string $msg + * @return void + */ + public function message($msg) + { + foreach($this as $client) + { + try + { + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $client, "targetmode" => TeamSpeak3::TEXTMSG_CLIENT)); + } + catch(TeamSpeak3_Adapter_ServerQuery_Exception $e) + { + /* ERROR_client_invalid_id */ + if($e->getCode() != 0x0200) throw $e; + } + } + } + + /** + * Downloads and returns the channel groups icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("iconid") || $this["iconid"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("iconid")); + $transfer = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + + foreach($this->getParent()->clientList() as $client) + { + if($client["client_channel_group_id"] == $this->getId()) + { + $this->nodeList[] = $client; + } + } + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_cg" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + return "group_channel"; + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "%"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["name"]; + } +} + diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Node/Client.php b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Client.php new file mode 100644 index 0000000..0744267 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Client.php @@ -0,0 +1,441 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Client + * @brief Class describing a TeamSpeak 3 client and all it's parameters. + */ +class TeamSpeak3_Node_Client extends TeamSpeak3_Node_Abstract +{ + /** + * The TeamSpeak3_Node_Client constructor. + * + * @param TeamSpeak3_Node_Server $server + * @param array $info + * @param string $index + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function __construct(TeamSpeak3_Node_Server $server, array $info, $index = "clid") + { + $this->parent = $server; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Changes the clients properties using given properties. + * + * @param array $properties + * @return void + */ + public function modify(array $properties) + { + $properties["clid"] = $this->getId(); + + $this->execute("clientedit", $properties); + $this->resetNodeInfo(); + } + + /** + * Changes the clients properties using given properties. + * + * @param array $properties + * @return void + */ + public function modifyDb(array $properties) + { + $this->getParent()->clientModifyDb($this["client_database_id"], $properties); + } + + /** + * Deletes the clients properties from the database. + * + * @return void + */ + public function deleteDb() + { + $this->getParent()->clientDeleteDb($this["client_database_id"]); + } + + /** + * Returns a list of properties from the database for the client. + * + * @return array + */ + public function infoDb() + { + return $this->getParent()->clientInfoDb($this["client_database_id"]); + } + + /** + * Sends a text message to the client. + * + * @param string $msg + * @return void + */ + public function message($msg) + { + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $this->getId(), "targetmode" => TeamSpeak3::TEXTMSG_CLIENT)); + } + + /** + * Moves the client to another channel. + * + * @param integer $cid + * @param string $cpw + * @return void + */ + public function move($cid, $cpw = null) + { + $this->getParent()->clientMove($this->getId(), $cid, $cpw); + } + + /** + * Kicks the client from his currently joined channel or from the server. + * + * @param integer $reasonid + * @param string $reasonmsg + * @return void + */ + public function kick($reasonid = TeamSpeak3::KICK_CHANNEL, $reasonmsg = null) + { + $this->getParent()->clientKick($this->getId(), $reasonid, $reasonmsg); + } + + /** + * Sends a poke message to the client. + * + * @param string $msg + * @return void + */ + public function poke($msg) + { + $this->getParent()->clientPoke($this->getId(), $msg); + } + + /** + * Bans the client from the server. Please note that this will create two separate + * ban rules for the targeted clients IP address and his unique identifier. + * + * @param integer $timeseconds + * @param string $reason + * @return array + */ + public function ban($timeseconds = null, $reason = null) + { + return $this->getParent()->clientBan($this->getId(), $timeseconds, $reason); + } + + /** + * Returns a list of custom properties for the client. + * + * @return array + */ + public function customInfo() + { + return $this->getParent()->customInfo($this["client_database_id"]); + } + + /** + * Returns an array containing the permission overview of the client. + * + * @param integer $cid + * @return array + */ + public function permOverview($cid) + { + return $this->execute("permoverview", array("cldbid" => $this["client_database_id"], "cid" => $cid, "permid" => 0))->toArray(); + } + + /** + * Returns a list of permissions defined for the client. + * + * @param boolean $permsid + * @return array + */ + public function permList($permsid = FALSE) + { + return $this->getParent()->clientPermList($this["client_database_id"], $permsid); + } + + /** + * Adds a set of specified permissions to the client. Multiple permissions can be added by providing + * the three parameters of each permission. + * + * @param integer $permid + * @param integer $permvalue + * @param integer $permskip + * @return void + */ + public function permAssign($permid, $permvalue, $permskip = FALSE) + { + $this->getParent()->clientPermAssign($this["client_database_id"], $permid, $permvalue, $permskip); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permAssignByName($permname, $permvalue, $permskip = FALSE) + { + $this->permAssign($permname, $permvalue, $permskip); + } + + /** + * Removes a set of specified permissions from a client. Multiple permissions can be removed at once. + * + * @param integer $permid + * @return void + */ + public function permRemove($permid) + { + $this->getParent()->clientPermRemove($this["client_database_id"], $permid); + } + + /** + * Alias for permRemove(). + * + * @deprecated + */ + public function permRemoveByName($permname) + { + $this->permRemove($permname); + } + + /** + * Sets the channel group of a client to the ID specified. + * + * @param integer $cid + * @param integer $cgid + * @return void + */ + public function setChannelGroup($cid, $cgid) + { + $this->getParent()->clientSetChannelGroup($this["client_database_id"], $cid, $cgid); + } + + /** + * Adds the client to the server group specified with $sgid. + * + * @param integer $sgid + * @return void + */ + public function addServerGroup($sgid) + { + $this->getParent()->serverGroupClientAdd($sgid, $this["client_database_id"]); + } + + /** + * Removes the client from the server group specified with $sgid. + * + * @param integer $sgid + * @return void + */ + public function remServerGroup($sgid) + { + $this->getParent()->serverGroupClientDel($sgid, $this["client_database_id"]); + } + + /** + * Returns the possible name of the clients avatar. + * + * @return TeamSpeak3_Helper_String + */ + public function avatarGetName() + { + return new TeamSpeak3_Helper_String("/avatar_" . $this["client_base64HashClientUID"]); + } + + /** + * Downloads and returns the clients avatar file content. + * + * @return TeamSpeak3_Helper_String + */ + public function avatarDownload() + { + if($this["client_flag_avatar"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->avatarGetName()); + $transfer = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * Returns a list of client connections using the same identity as this client. + * + * @return array + */ + public function getClones() + { + return $this->execute("clientgetids", array("cluid" => $this["client_unique_identifier"]))->toAssocArray("clid"); + } + + /** + * Returns the revision/build number from the clients version string. + * + * @return integer + */ + public function getRev() + { + return $this["client_type"] ? null : $this["client_version"]->section("[", 1)->filterDigits(); + } + + /** + * Returns all server and channel groups the client is currently residing in. + * + * @return array + */ + public function memberOf() + { + $groups = array($this->getParent()->channelGroupGetById($this["client_channel_group_id"])); + + foreach(explode(",", $this["client_servergroups"]) as $sgid) + { + $groups[] = $this->getParent()->serverGroupGetById($sgid); + } + + return $groups; + } + + /** + * Downloads and returns the clients icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("client_icon_id") || $this["client_icon_id"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("client_icon_id")); + $transfer = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * Sends a plugin command to the client. + * + * @param string $plugin + * @param string $data + * @return void + */ + public function sendPluginCmd($plugin, $data) + { + $this->execute("plugincmd", array("name" => $plugin, "data" => $data, "targetmode" => TeamSpeak3::PLUGINCMD_CLIENT, "target" => $this->getId())); + } + + /** + * @ignore + */ + protected function fetchNodeInfo() + { + if($this->offsetExists("client_type") && $this["client_type"] == 1) return; + + $this->nodeInfo = array_merge($this->nodeInfo, $this->execute("clientinfo", array("clid" => $this->getId()))->toList()); + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_cl" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + if($this["client_type"]) + { + return "client_query"; + } + elseif($this["client_away"]) + { + return "client_away"; + } + elseif(!$this["client_output_hardware"]) + { + return "client_snd_disabled"; + } + elseif($this["client_output_muted"]) + { + return "client_snd_muted"; + } + elseif(!$this["client_input_hardware"]) + { + return "client_mic_disabled"; + } + elseif($this["client_input_muted"]) + { + return "client_mic_muted"; + } + elseif($this["client_is_channel_commander"]) + { + return $this["client_flag_talking"] ? "client_cc_talk" : "client_cc_idle"; + } + else + { + return $this["client_flag_talking"] ? "client_talk" : "client_idle"; + } + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "@"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["client_nickname"]; + } +} + diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Node/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Exception.php new file mode 100644 index 0000000..2d1b769 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Exception + * @brief Enhanced exception class for TeamSpeak3_Node_Abstract objects. + */ +class TeamSpeak3_Node_Exception extends TeamSpeak3_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Node/Host.php b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Host.php new file mode 100644 index 0000000..a6e0913 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Host.php @@ -0,0 +1,1202 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Host + * @brief Class describing a TeamSpeak 3 server instance and all it's parameters. + */ +class TeamSpeak3_Node_Host extends TeamSpeak3_Node_Abstract +{ + /** + * @ignore + */ + protected $whoami = null; + + /** + * @ignore + */ + protected $version = null; + + /** + * @ignore + */ + protected $serverList = null; + + /** + * @ignore + */ + protected $permissionEnds = null; + + /** + * @ignore + */ + protected $permissionList = null; + + /** + * @ignore + */ + protected $permissionCats = null; + + /** + * @ignore + */ + protected $predefined_query_name = null; + + /** + * @ignore + */ + protected $exclude_query_clients = FALSE; + + /** + * @ignore + */ + protected $start_offline_virtual = FALSE; + + /** + * @ignore + */ + protected $sort_clients_channels = FALSE; + + /** + * The TeamSpeak3_Node_Host constructor. + * + * @param TeamSpeak3_Adapter_ServerQuery $squery + * @return TeamSpeak3_Node_Host + */ + public function __construct(TeamSpeak3_Adapter_ServerQuery $squery) + { + $this->parent = $squery; + } + + /** + * Returns the primary ID of the selected virtual server. + * + * @return integer + */ + public function serverSelectedId() + { + return $this->whoamiGet("virtualserver_id", 0); + } + + /** + * Returns the primary UDP port of the selected virtual server. + * + * @return integer + */ + public function serverSelectedPort() + { + return $this->whoamiGet("virtualserver_port", 0); + } + + /** + * Returns the servers version information including platform and build number. + * + * @param string $ident + * @return mixed + */ + public function version($ident = null) + { + if($this->version === null) + { + $this->version = $this->request("version")->toList(); + } + + return ($ident && isset($this->version[$ident])) ? $this->version[$ident] : $this->version; + } + + /** + * Selects a virtual server by ID to allow further interaction. + * + * @param integer $sid + * @param boolean $virtual + * @return void + */ + public function serverSelect($sid, $virtual = null) + { + if($this->whoami !== null && $this->serverSelectedId() == $sid) return; + + $virtual = ($virtual !== null) ? $virtual : $this->start_offline_virtual; + $getargs = func_get_args(); + + $this->execute("use", array("sid" => $sid, $virtual ? "-virtual" : null)); + + if($sid != 0 && $this->predefined_query_name !== null) + { + $this->execute("clientupdate", array("client_nickname" => (string) $this->predefined_query_name)); + } + + $this->whoamiReset(); + + $this->setStorage("_server_use", array(__FUNCTION__, $getargs)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerselected", $this); + } + + /** + * Alias for serverSelect(). + * + * @param integer $sid + * @param boolean $virtual + * @return void + */ + public function serverSelectById($sid, $virtual = null) + { + $this->serverSelect($sid, $virtual); + } + + /** + * Selects a virtual server by UDP port to allow further interaction. + * + * @param integer $port + * @param boolean $virtual + * @return void + */ + public function serverSelectByPort($port, $virtual = null) + { + if($this->whoami !== null && $this->serverSelectedPort() == $port) return; + + $virtual = ($virtual !== null) ? $virtual : $this->start_offline_virtual; + $getargs = func_get_args(); + + $this->execute("use", array("port" => $port, $virtual ? "-virtual" : null)); + + if($port != 0 && $this->predefined_query_name !== null) + { + $this->execute("clientupdate", array("client_nickname" => (string) $this->predefined_query_name)); + } + + $this->whoamiReset(); + + $this->setStorage("_server_use", array(__FUNCTION__, $getargs)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerselected", $this); + } + + /** + * Deselects the active virtual server. + * + * @return void + */ + public function serverDeselect() + { + $this->serverSelect(0); + + $this->delStorage("_server_use"); + } + + /** + * Returns the ID of a virtual server matching the given port. + * + * @param integer $port + * @return integer + */ + public function serverIdGetByPort($port) + { + $sid = $this->execute("serveridgetbyport", array("virtualserver_port" => $port))->toList(); + + return $sid["server_id"]; + } + + /** + * Returns the port of a virtual server matching the given ID. + * + * @param integer $sid + * @return integer + */ + public function serverGetPortById($sid) + { + if(!array_key_exists((string) $sid, $this->serverList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); + } + + return $this->serverList[intval((string) $sid)]["virtualserver_port"]; + } + + /** + * Returns the TeamSpeak3_Node_Server object matching the currently selected ID. + * + * @return TeamSpeak3_Node_Server + */ + public function serverGetSelected() + { + return $this->serverGetById($this->serverSelectedId()); + } + + /** + * Returns the TeamSpeak3_Node_Server object matching the given ID. + * + * @param integer $sid + * @return TeamSpeak3_Node_Server + */ + public function serverGetById($sid) + { + $this->serverSelectById($sid); + + return new TeamSpeak3_Node_Server($this, array("virtualserver_id" => intval($sid))); + } + + /** + * Returns the TeamSpeak3_Node_Server object matching the given port number. + * + * @param integer $port + * @return TeamSpeak3_Node_Server + */ + public function serverGetByPort($port) + { + $this->serverSelectByPort($port); + + return new TeamSpeak3_Node_Server($this, array("virtualserver_id" => $this->serverSelectedId())); + } + + /** + * Returns the first TeamSpeak3_Node_Server object matching the given name. + * + * @param string $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Server + */ + public function serverGetByName($name) + { + foreach($this->serverList() as $server) + { + if($server["virtualserver_name"] == $name) return $server; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); + } + + /** + * Returns the first TeamSpeak3_Node_Server object matching the given unique identifier. + * + * @param string $uid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Server + */ + public function serverGetByUid($uid) + { + foreach($this->serverList() as $server) + { + if($server["virtualserver_unique_identifier"] == $uid) return $server; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); + } + + /** + * Returns the first TeamSpeak3_Node_Server object matching the given TSDNS hostname. Like the + * TeamSpeak 3 Client, this method will start looking for a TSDNS server on the second-level + * domain including a fallback to the third-level domain of the specified $tsdns parameter. + * + * @param string $tsdns + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Server + */ + public function serverGetByTSDNS($tsdns) + { + $parts = TeamSpeak3_Helper_Uri::getFQDNParts($tsdns); + $query = TeamSpeak3_Helper_String::factory(array_shift($parts)); + + while($part = array_shift($parts)) + { + $query->prepend($part); + + try + { + $port = TeamSpeak3::factory("tsdns://" . $query . "/?timeout=3")->resolve($tsdns)->section(":", 1); + + return $this->serverGetByPort($port == "" ? 9987 : $port); + } + catch(TeamSpeak3_Transport_Exception $e) + { + /* skip "Connection timed out" and "Connection refused" */ + if($e->getCode() != 10060 && $e->getCode() != 10061) throw $e; + } + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); + } + + /** + * Creates a new virtual server using given properties and returns an assoc + * array containing the new ID and initial admin token. + * + * @param array $properties + * @return array + */ + public function serverCreate(array $properties = array()) + { + $this->serverListReset(); + + $detail = $this->execute("servercreate", $properties)->toList(); + $server = new TeamSpeak3_Node_Server($this, array("virtualserver_id" => intval($detail["sid"]))); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServercreated", $this, $detail["sid"]); + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyTokencreated", $server, $detail["token"]); + + return $detail; + } + + /** + * Deletes the virtual server specified by ID. + * + * @param integer $sid + * @return void + */ + public function serverDelete($sid) + { + $this->serverListReset(); + + $this->execute("serverdelete", array("sid" => $sid)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerdeleted", $this, $sid); + } + + /** + * Starts the virtual server specified by ID. + * + * @param integer $sid + * @return void + */ + public function serverStart($sid) + { + if($sid == $this->serverSelectedId()) + { + $this->serverDeselect(); + } + + $this->execute("serverstart", array("sid" => $sid)); + $this->serverListReset(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerstarted", $this, $sid); + } + + /** + * Stops the virtual server specified by ID. + * + * @param integer $sid + * @return void + */ + public function serverStop($sid) + { + if($sid == $this->serverSelectedId()) + { + $this->serverDeselect(); + } + + $this->execute("serverstop", array("sid" => $sid)); + $this->serverListReset(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerstopped", $this, $sid); + } + + /** + * Stops the entire TeamSpeak 3 Server instance by shutting down the process. + * + * @return void + */ + public function serverStopProcess() + { + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServershutdown", $this); + + $this->execute("serverprocessstop"); + } + + /** + * Returns an array filled with TeamSpeak3_Node_Server objects. + * + * @param array $filter + * @return array + */ + public function serverList(array $filter = array()) + { + if($this->serverList === null) + { + $servers = $this->request("serverlist -uid")->toAssocArray("virtualserver_id"); + + $this->serverList = array(); + + foreach($servers as $sid => $server) + { + $this->serverList[$sid] = new TeamSpeak3_Node_Server($this, $server); + } + + $this->resetNodeList(); + } + + return $this->filterList($this->serverList, $filter); + } + + /** + * Resets the list of virtual servers. + * + * @return void + */ + public function serverListReset() + { + $this->resetNodeList(); + $this->serverList = null; + } + + /** + * Returns a list of IP addresses used by the server instance on multi-homed machines. + * + * @return array + */ + public function bindingList($subsystem = "voice") + { + return $this->execute("bindinglist", array("subsystem" => $subsystem))->toArray(); + } + + /** + * Returns a list of permissions available on the server instance. + * + * @return array + */ + public function permissionList() + { + if($this->permissionList === null) + { + $this->fetchPermissionList(); + } + + foreach($this->permissionList as $permname => $permdata) + { + if(isset($permdata["permcatid"]) && $permdata["permgrant"]) + { + continue; + } + + $this->permissionList[$permname]["permcatid"] = $this->permissionGetCategoryById($permdata["permid"]); + $this->permissionList[$permname]["permgrant"] = $this->permissionGetGrantById($permdata["permid"]); + + $grantsid = "i_needed_modify_power_" . substr($permname, 2); + + if(!$permdata["permname"]->startsWith("i_needed_modify_power_") && !isset($this->permissionList[$grantsid])) + { + $this->permissionList[$grantsid]["permid"] = $this->permissionList[$permname]["permgrant"]; + $this->permissionList[$grantsid]["permname"] = TeamSpeak3_Helper_String::factory($grantsid); + $this->permissionList[$grantsid]["permdesc"] = null; + $this->permissionList[$grantsid]["permcatid"] = 0xFF; + $this->permissionList[$grantsid]["permgrant"] = $this->permissionList[$permname]["permgrant"]; + } + } + + return $this->permissionList; + } + + /** + * Returns a list of permission categories available on the server instance. + * + * @return array + */ + public function permissionCats() + { + if($this->permissionCats === null) + { + $this->fetchPermissionCats(); + } + + return $this->permissionCats; + } + + /** + * Returns a list of permission category endings available on the server instance. + * + * @return array + */ + public function permissionEnds() + { + if($this->permissionEnds === null) + { + $this->fetchPermissionList(); + } + + return $this->permissionCats; + } + + /** + * Returns an array filled with all permission categories known to the server including + * their ID, name and parent. + * + * @return array + */ + public function permissionTree() + { + $permtree = array(); + + foreach($this->permissionCats() as $key => $val) + { + $permtree[$val]["permcatid"] = $val; + $permtree[$val]["permcathex"] = "0x" . dechex($val); + $permtree[$val]["permcatname"] = TeamSpeak3_Helper_String::factory(TeamSpeak3_Helper_Convert::permissionCategory($val)); + $permtree[$val]["permcatparent"] = $permtree[$val]["permcathex"]{3} == 0 ? 0 : hexdec($permtree[$val]["permcathex"]{2} . 0); + $permtree[$val]["permcatchilren"] = 0; + $permtree[$val]["permcatcount"] = 0; + + if(isset($permtree[$permtree[$val]["permcatparent"]])) + { + $permtree[$permtree[$val]["permcatparent"]]["permcatchilren"]++; + } + + if($permtree[$val]["permcatname"]->contains("/")) + { + $permtree[$val]["permcatname"] = $permtree[$val]["permcatname"]->section("/", 1)->trim(); + } + + foreach($this->permissionList() as $permission) + { + if($permission["permid"]["permcatid"] == $val) + { + $permtree[$val]["permcatcount"]++; + } + } + } + + return $permtree; + } + + /** + * Returns the IDs of all clients, channels or groups using the permission with the + * specified ID. + * + * @param integer $permid + * @return array + */ + public function permissionFind($permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + return $this->execute("permfind", array($permident => $permid))->toArray(); + } + + /** + * Returns the ID of the permission matching the given name. + * + * @param string $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return integer + */ + public function permissionGetIdByName($name) + { + if(!array_key_exists((string) $name, $this->permissionList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid permission ID", 0xA02); + } + + return $this->permissionList[(string) $name]["permid"]; + } + + /** + * Returns the name of the permission matching the given ID. + * + * @param integer $permid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Helper_String + */ + public function permissionGetNameById($permid) + { + foreach($this->permissionList() as $name => $perm) + { + if($perm["permid"] == $permid) return new TeamSpeak3_Helper_String($name); + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid permission ID", 0xA02); + } + + /** + * Returns the internal category of the permission matching the given ID. + * + * All pre-3.0.7 permission IDs are are 2 bytes wide. The first byte identifies the category while + * the second byte is the permission count within that group. + * + * @param integer $permid + * @return integer + */ + public function permissionGetCategoryById($permid) + { + if(!is_numeric($permid)) + { + $permid = $this->permissionGetIdByName($permid); + } + + if($permid < 0x1000) + { + if($this->permissionEnds === null) + { + $this->fetchPermissionList(); + } + + if($this->permissionCats === null) + { + $this->fetchPermissionCats(); + } + + $catids = array_values($this->permissionCats()); + + foreach($this->permissionEnds as $key => $val) + { + if($val >= $permid && isset($catids[$key])) + { + return $catids[$key]; + } + } + + return 0; + } + else + { + return (int) $permid >> 8; + } + } + + /** + * Returns the internal ID of the i_needed_modify_power_* or grant permission. + * + * Every permission has an associated i_needed_modify_power_* permission, for example b_client_ban_create has an + * associated permission called i_needed_modify_power_client_ban_create. + * + * @param integer $permid + * @return integer + */ + public function permissionGetGrantById($permid) + { + if(!is_numeric($permid)) + { + $permid = $this->permissionGetIdByName($permid); + } + + if($permid < 0x1000) + { + return (int) $permid+0x8000; + } + else + { + return (int) bindec(substr(decbin($permid), -8))+0xFF00; + } + } + + /** + * Adds a set of specified permissions to all regular server groups on all virtual servers. The target groups will + * be identified by the value of their i_group_auto_update_type permission specified with $sgtype. + * + * @param integer $sgtype + * @param integer $permid + * @param integer $permvalue + * @param integer $permnegated + * @param integer $permskip + * @return void + */ + public function serverGroupPermAutoAssign($sgtype, $permid, $permvalue, $permnegated = FALSE, $permskip = FALSE) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("servergroupautoaddperm", array("sgtype" => $sgtype, $permident => $permid, "permvalue" => $permvalue, "permnegated" => $permnegated, "permskip" => $permskip)); + } + + /** + * Removes a set of specified permissions from all regular server groups on all virtual servers. The target groups + * will be identified by the value of their i_group_auto_update_type permission specified with $sgtype. + * + * @param integer $sgtype + * @param integer $permid + * @return void + */ + public function serverGroupPermAutoRemove($sgtype, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("servergroupautodelperm", array("sgtype" => $sgtype, $permident => $permid)); + } + + /** + * Returns an array containing the value of a specified permission for your own client. + * + * @param integer $permid + * @return array + */ + public function selfPermCheck($permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + return $this->execute("permget", array($permident => $permid))->toAssocArray("permsid"); + } + + /** + * Changes the server instance configuration using given properties. + * + * @param array $properties + * @return void + */ + public function modify(array $properties) + { + $this->execute("instanceedit", $properties); + $this->resetNodeInfo(); + } + + /** + * Sends a text message to all clients on all virtual servers in the TeamSpeak 3 Server instance. + * + * @param string $msg + * @return void + */ + public function message($msg) + { + $this->execute("gm", array("msg" => $msg)); + } + + /** + * Displays a specified number of entries (1-100) from the servers log. + * + * @param integer $lines + * @param integer $begin_pos + * @param boolean $reverse + * @param boolean $instance + * @return array + */ + public function logView($lines = 30, $begin_pos = null, $reverse = null, $instance = TRUE) + { + return $this->execute("logview", array("lines" => $lines, "begin_pos" => $begin_pos, "instance" => $instance, "reverse" => $reverse))->toArray(); + } + + /** + * Writes a custom entry into the server instance log. + * + * @param string $logmsg + * @param integer $loglevel + * @return void + */ + public function logAdd($logmsg, $loglevel = TeamSpeak3::LOGLEVEL_INFO) + { + $sid = $this->serverSelectedId(); + + $this->serverDeselect(); + $this->execute("logadd", array("logmsg" => $logmsg, "loglevel" => $loglevel)); + $this->serverSelect($sid); + } + + /** + * Authenticates with the TeamSpeak 3 Server instance using given ServerQuery login credentials. + * + * @param string $username + * @param string $password + * @return void + */ + public function login($username, $password) + { + $this->execute("login", array("client_login_name" => $username, "client_login_password" => $password)); + $this->whoamiReset(); + + $crypt = new TeamSpeak3_Helper_Crypt($username); + + $this->setStorage("_login_user", $username); + $this->setStorage("_login_pass", $crypt->encrypt($password)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyLogin", $this); + } + + /** + * Deselects the active virtual server and logs out from the server instance. + * + * @return void + */ + public function logout() + { + $this->request("logout"); + $this->whoamiReset(); + + $this->delStorage("_login_user"); + $this->delStorage("_login_pass"); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyLogout", $this); + } + + /** + * Returns information about your current ServerQuery connection. + * + * @return array + */ + public function whoami() + { + if($this->whoami === null) + { + $this->whoami = $this->request("whoami")->toList(); + } + + return $this->whoami; + } + + /** + * Returns a single value from the current ServerQuery connection info. + * + * @param string $ident + * @param mixed $default + * @return mixed + */ + public function whoamiGet($ident, $default = null) + { + if(array_key_exists($ident, $this->whoami())) + { + return $this->whoami[$ident]; + } + + return $default; + } + + /** + * Sets a single value in the current ServerQuery connection info. + * + * @param string $ident + * @param mixed $value + * @return mixed + */ + public function whoamiSet($ident, $value = null) + { + $this->whoami(); + + $this->whoami[$ident] = (is_numeric($value)) ? (int) $value : TeamSpeak3_Helper_String::factory($value); + } + + /** + * Resets the current ServerQuery connection info. + * + * @return void + */ + public function whoamiReset() + { + $this->whoami = null; + } + + /** + * Returns the hostname or IPv4 address the adapter is connected to. + * + * @return string + */ + public function getAdapterHost() + { + return $this->getParent()->getTransportHost(); + } + + /** + * Returns the network port the adapter is connected to. + * + * @return string + */ + public function getAdapterPort() + { + return $this->getParent()->getTransportPort(); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $servers = $this->serverList(); + + foreach($servers as $server) + { + $this->nodeList[] = $server; + } + } + + /** + * @ignore + */ + protected function fetchNodeInfo() + { + $info1 = $this->request("hostinfo")->toList(); + $info2 = $this->request("instanceinfo")->toList(); + + $this->nodeInfo = array_merge($this->nodeInfo, $info1, $info2); + } + + /** + * @ignore + */ + protected function fetchPermissionList() + { + $reply = $this->request("permissionlist -new")->toArray(); + $start = 1; + + $this->permissionEnds = array(); + $this->permissionList = array(); + + foreach($reply as $line) + { + if(array_key_exists("group_id_end", $line)) + { + $this->permissionEnds[] = $line["group_id_end"]; + } + else + { + $this->permissionList[$line["permname"]->toString()] = array_merge(array("permid" => $start++), $line); + } + } + } + + /** + * @ignore + */ + protected function fetchPermissionCats() + { + $permcats = array(); + $reflects = new ReflectionClass("TeamSpeak3"); + + foreach($reflects->getConstants() as $key => $val) + { + if(!TeamSpeak3_Helper_String::factory($key)->startsWith("PERM_CAT") || $val == 0xFF) + { + continue; + } + + $permcats[$key] = $val; + } + + $this->permissionCats = $permcats; + } + + /** + * Sets a pre-defined nickname for ServerQuery clients which will be used automatically + * after selecting a virtual server. + * + * @param string $name + * @return void + */ + public function setPredefinedQueryName($name = null) + { + $this->setStorage("_query_nick", $name); + + $this->predefined_query_name = $name; + } + + /** + * Returns the pre-defined nickname for ServerQuery clients which will be used automatically + * after selecting a virtual server. + * + * @return string + */ + public function getPredefinedQueryName() + { + return $this->predefined_query_name; + } + + /** + * Sets the option to decide whether ServerQuery clients should be excluded from node + * lists or not. + * + * @param boolean $exclude + * @return void + */ + public function setExcludeQueryClients($exclude = FALSE) + { + $this->setStorage("_query_hide", $exclude); + + $this->exclude_query_clients = $exclude; + } + + /** + * Returns the option to decide whether ServerQuery clients should be excluded from node + * lists or not. + * + * @return boolean + */ + public function getExcludeQueryClients() + { + return $this->exclude_query_clients; + } + + /** + * Sets the option to decide whether offline servers will be started in virtual mode + * by default or not. + * + * @param boolean $virtual + * @return void + */ + public function setUseOfflineAsVirtual($virtual = FALSE) + { + $this->setStorage("_do_virtual", $virtual); + + $this->start_offline_virtual = $virtual; + } + + /** + * Returns the option to decide whether offline servers will be started in virtual mode + * by default or not. + * + * @return boolean + */ + public function getUseOfflineAsVirtual() + { + return $this->start_offline_virtual; + } + + /** + * Sets the option to decide whether clients should be sorted before sub-channels to support + * the new TeamSpeak 3 Client display mode or not. + * + * @param boolean $first + * @return void + */ + public function setLoadClientlistFirst($first = FALSE) + { + $this->setStorage("_client_top", $first); + + $this->sort_clients_channels = $first; + } + + /** + * Returns the option to decide whether offline servers will be started in virtual mode + * by default or not. + * + * @return boolean + */ + public function getLoadClientlistFirst() + { + return $this->sort_clients_channels; + } + + /** + * Returns the underlying TeamSpeak3_Adapter_ServerQuery object. + * + * @return TeamSpeak3_Adapter_ServerQuery + */ + public function getAdapter() + { + return $this->getParent(); + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return "ts3_h"; + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + return "host"; + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "+"; + } + + /** + * Re-authenticates with the TeamSpeak 3 Server instance using given ServerQuery login + * credentials and re-selects a previously selected virtual server. + * + * @return void + */ + public function __wakeup() + { + $username = $this->getStorage("_login_user"); + $password = $this->getStorage("_login_pass"); + + if($username && $password) + { + $crypt = new TeamSpeak3_Helper_Crypt($username); + + $this->login($username, $crypt->decrypt($password)); + } + + $this->predefined_query_name = $this->getStorage("_query_nick"); + $this->exclude_query_clients = $this->getStorage("_query_hide", FALSE); + $this->start_offline_virtual = $this->getStorage("_do_virtual", FALSE); + $this->sort_clients_channels = $this->getStorage("_client_top", FALSE); + + if($server = $this->getStorage("_server_use")) + { + $func = array_shift($server); + $args = array_shift($server); + + try + { + call_user_func_array(array($this, $func), $args); + } + catch(Exception $e) + { + $class = get_class($e); + + throw new $class($e->getMessage(), $e->getCode()); + } + } + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this->getAdapterHost(); + } +} + diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Node/Server.php b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Server.php new file mode 100644 index 0000000..0d15926 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Server.php @@ -0,0 +1,2536 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Server + * @brief Class describing a TeamSpeak 3 virtual server and all it's parameters. + */ +class TeamSpeak3_Node_Server extends TeamSpeak3_Node_Abstract +{ + /** + * @ignore + */ + protected $channelList = null; + + /** + * @ignore + */ + protected $clientList = null; + + /** + * @ignore + */ + protected $sgroupList = null; + + /** + * @ignore + */ + protected $cgroupList = null; + + /** + * The TeamSpeak3_Node_Server constructor. + * + * @param TeamSpeak3_Node_Host $host + * @param array $info + * @param string $index + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Server + */ + public function __construct(TeamSpeak3_Node_Host $host, array $info, $index = "virtualserver_id") + { + $this->parent = $host; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Sends a prepared command to the server and returns the result. + * + * @param string $cmd + * @param boolean $throw + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function request($cmd, $throw = TRUE) + { + if($this->getId() != $this->getParent()->serverSelectedId()) + { + $this->getParent()->serverSelect($this->getId()); + } + + return $this->getParent()->request($cmd, $throw); + } + + /** + * Returns an array filled with TeamSpeak3_Node_Channel objects. + * + * @param array $filter + * @return array + */ + public function channelList(array $filter = array()) + { + if($this->channelList === null) + { + $channels = $this->request("channellist -topic -flags -voice -limits -icon")->toAssocArray("cid"); + + $this->channelList = array(); + + foreach($channels as $cid => $channel) + { + $this->channelList[$cid] = new TeamSpeak3_Node_Channel($this, $channel); + } + + $this->resetNodeList(); + } + + return $this->filterList($this->channelList, $filter); + } + + /** + * Resets the list of channels online. + * + * @return void + */ + public function channelListReset() + { + $this->resetNodeList(); + $this->channelList = null; + } + + /** + * Creates a new channel using given properties and returns the new ID. + * + * @param array $properties + * @return integer + */ + public function channelCreate(array $properties) + { + $cid = $this->execute("channelcreate", $properties)->toList(); + $this->channelListReset(); + + if(!isset($properties["channel_flag_permanent"]) && !isset($properties["channel_flag_semi_permanent"])) + { + $this->getParent()->whoamiSet("client_channel_id", $cid["cid"]); + } + + return $cid["cid"]; + } + + /** + * Deletes the channel specified by $cid. + * + * @param integer $cid + * @param boolean $force + * @return void + */ + public function channelDelete($cid, $force = FALSE) + { + $this->execute("channeldelete", array("cid" => $cid, "force" => $force)); + $this->channelListReset(); + + if(($cid instanceof TeamSpeak3_Node_Abstract ? $cid->getId() : $cid) == $this->whoamiGet("client_channel_id")) + { + $this->getParent()->whoamiReset(); + } + } + + /** + * Moves the channel specified by $cid to the parent channel specified with $pid. + * + * @param integer $cid + * @param integer $pid + * @param integer $order + * @return void + */ + public function channelMove($cid, $pid, $order = null) + { + $this->execute("channelmove", array("cid" => $cid, "cpid" => $pid, "order" => $order)); + $this->channelListReset(); + } + + /** + * Returns TRUE if the given TeamSpeak3_Node_Channel object is a spacer. + * + * @param TeamSpeak3_Node_Channel $channel + * @return boolean + */ + public function channelIsSpacer(TeamSpeak3_Node_Channel $channel) + { + return (preg_match("/\[[^\]]*spacer[^\]]*\]/", $channel) && $channel["channel_flag_permanent"] && !$channel["pid"]) ? TRUE : FALSE; + } + + /** + * Creates a new channel spacer and returns the new ID. The first parameter $ident is used to create a + * unique spacer name on the virtual server. + * + * @param string $ident + * @param mixed $type + * @param integer $align + * @param integer $order + * @param integer $maxclients + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return integer + */ + public function channelSpacerCreate($ident, $type = TeamSpeak3::SPACER_SOLIDLINE, $align = TeamSpeak3::SPACER_ALIGN_REPEAT, $order = null, $maxclients = 0) + { + $properties = array( + "channel_name_phonetic" => "channel spacer", + "channel_codec" => TeamSpeak3::CODEC_OPUS_VOICE, + "channel_codec_quality" => 0x00, + "channel_flag_permanent" => TRUE, + "channel_flag_maxclients_unlimited" => FALSE, + "channel_flag_maxfamilyclients_unlimited" => FALSE, + "channel_flag_maxfamilyclients_inherited" => FALSE, + "channel_maxclients" => $maxclients, + "channel_order" => $order, + ); + + switch($align) + { + case TeamSpeak3::SPACER_ALIGN_REPEAT: + $properties["channel_name"] = "[*spacer" . strval($ident) . "]"; + break; + + case TeamSpeak3::SPACER_ALIGN_LEFT: + $properties["channel_name"] = "[lspacer" . strval($ident) . "]"; + break; + + case TeamSpeak3::SPACER_ALIGN_RIGHT: + $properties["channel_name"] = "[rspacer" . strval($ident) . "]"; + break; + + case TeamSpeak3::SPACER_ALIGN_CENTER: + $properties["channel_name"] = "[cspacer" . strval($ident) . "]"; + break; + + default: + throw new TeamSpeak3_Adapter_ServerQuery_Exception("missing required parameter", 0x606); + break; + } + + switch($type) + { + case (string) TeamSpeak3::SPACER_SOLIDLINE: + $properties["channel_name"] .= "___"; + break; + + case (string) TeamSpeak3::SPACER_DASHLINE: + $properties["channel_name"] .= "---"; + break; + + case (string) TeamSpeak3::SPACER_DOTLINE: + $properties["channel_name"] .= "..."; + break; + + case (string) TeamSpeak3::SPACER_DASHDOTLINE: + $properties["channel_name"] .= "-.-"; + break; + + case (string) TeamSpeak3::SPACER_DASHDOTDOTLINE: + $properties["channel_name"] .= "-.."; + break; + + default: + $properties["channel_name"] .= strval($type); + break; + } + + return $this->channelCreate($properties); + } + + /** + * Returns the possible type of a channel spacer. + * + * @param integer $cid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return integer + */ + public function channelSpacerGetType($cid) + { + $channel = $this->channelGetById($cid); + + if(!$this->channelIsSpacer($channel)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channel flags", 0x307); + } + + switch($channel["channel_name"]->section("]", 1)) + { + case "___": + return TeamSpeak3::SPACER_SOLIDLINE; + + case "---": + return TeamSpeak3::SPACER_DASHLINE; + + case "...": + return TeamSpeak3::SPACER_DOTLINE; + + case "-.-": + return TeamSpeak3::SPACER_DASHDOTLINE; + + case "-..": + return TeamSpeak3::SPACER_DASHDOTDOTLINE; + + default: + return TeamSpeak3::SPACER_CUSTOM; + } + } + + /** + * Returns the possible alignment of a channel spacer. + * + * @param integer $cid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return integer + */ + public function channelSpacerGetAlign($cid) + { + $channel = $this->channelGetById($cid); + + if(!$this->channelIsSpacer($channel) || !preg_match("/\[(.*)spacer.*\]/", $channel, $matches) || !isset($matches[1])) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channel flags", 0x307); + } + + switch($matches[1]) + { + case "*": + return TeamSpeak3::SPACER_ALIGN_REPEAT; + + case "c": + return TeamSpeak3::SPACER_ALIGN_CENTER; + + case "r": + return TeamSpeak3::SPACER_ALIGN_RIGHT; + + default: + return TeamSpeak3::SPACER_ALIGN_LEFT; + } + } + + /** + * Returns a list of permissions defined for a specific channel. + * + * @param integer $cid + * @param boolean $permsid + * @return array + */ + public function channelPermList($cid, $permsid = FALSE) + { + return $this->execute("channelpermlist", array("cid" => $cid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to a channel. Multiple permissions can be added by + * providing the two parameters of each permission. + * + * @param integer $cid + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function channelPermAssign($cid, $permid, $permvalue) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channeladdperm", array("cid" => $cid, $permident => $permid, "permvalue" => $permvalue)); + } + + /** + * Removes a set of specified permissions from a channel. Multiple permissions can be removed at once. + * + * @param integer $cid + * @param integer $permid + * @return void + */ + public function channelPermRemove($cid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channeldelperm", array("cid" => $cid, $permident => $permid)); + } + + /** + * Returns a list of permissions defined for a client in a specific channel. + * + * @param integer $cid + * @param integer $cldbid + * @param boolean $permsid + * @return array + */ + public function channelClientPermList($cid, $cldbid, $permsid = FALSE) + { + return $this->execute("channelclientpermlist", array("cid" => $cid, "cldbid" => $cldbid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to a client in a specific channel. Multiple permissions can be added by + * providing the two parameters of each permission. + * + * @param integer $cid + * @param integer $cldbid + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function channelClientPermAssign($cid, $cldbid, $permid, $permvalue) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channelclientaddperm", array("cid" => $cid, "cldbid" => $cldbid, $permident => $permid, "permvalue" => $permvalue)); + } + + /** + * Removes a set of specified permissions from a client in a specific channel. Multiple permissions can be removed at once. + * + * @param integer $cid + * @param integer $cldbid + * @param integer $permid + * @return void + */ + public function channelClientPermRemove($cid, $cldbid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channelclientdelperm", array("cid" => $cid, "cldbid" => $cldbid, $permident => $permid)); + } + + /** + * Returns a list of files and directories stored in the specified channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $path + * @param boolean $recursive + * @return array + */ + public function channelFileList($cid, $cpw = "", $path = "/", $recursive = FALSE) + { + $files = $this->execute("ftgetfilelist", array("cid" => $cid, "cpw" => $cpw, "path" => $path))->toArray(); + $count = count($files); + + for($i = 0; $i < $count; $i++) + { + $files[$i]["sid"] = $this->getId(); + $files[$i]["cid"] = $files[0]["cid"]; + $files[$i]["path"] = $files[0]["path"]; + $files[$i]["src"] = new TeamSpeak3_Helper_String($cid ? $files[$i]["path"] : "/"); + + if(!$files[$i]["src"]->endsWith("/")) + { + $files[$i]["src"]->append("/"); + } + + $files[$i]["src"]->append($files[$i]["name"]); + + if($recursive && $files[$i]["type"] == TeamSpeak3::FILE_TYPE_DIRECTORY) + { + $files = array_merge($files, $this->channelFileList($cid, $cpw, $path . $files[$i]["name"], $recursive)); + } + } + + uasort($files, array(__CLASS__, "sortFileList")); + + return $files; + } + + /** + * Returns detailed information about the specified file stored in a channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $name + * @return array + */ + public function channelFileInfo($cid, $cpw = "", $name = "/") + { + return array_pop($this->execute("ftgetfileinfo", array("cid" => $cid, "cpw" => $cpw, "name" => $name))->toArray()); + } + + /** + * Renames a file in a channels file repository. If the two parameters $tcid and $tcpw are specified, the file + * will be moved into another channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $oldname + * @param string $newname + * @param integer $tcid + * @param string $tcpw + * @return void + */ + public function channelFileRename($cid, $cpw = "", $oldname = "/", $newname = "/", $tcid = null, $tcpw = null) + { + $this->execute("ftrenamefile", array("cid" => $cid, "cpw" => $cpw, "oldname" => $oldname, "newname" => $newname, "tcid" => $tcid, "tcpw" => $tcpw)); + } + + /** + * Deletes one or more files stored in a channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $name + * @return void + */ + public function channelFileDelete($cid, $cpw = "", $name = "/") + { + $this->execute("ftdeletefile", array("cid" => $cid, "cpw" => $cpw, "name" => $name)); + } + + /** + * Creates new directory in a channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $dirname + * @return void + */ + public function channelDirCreate($cid, $cpw = "", $dirname = "/") + { + $this->execute("ftcreatedir", array("cid" => $cid, "cpw" => $cpw, "dirname" => $dirname)); + } + + /** + * Returns the level of a channel. + * + * @param integer $cid + * @return integer + */ + public function channelGetLevel($cid) + { + $channel = $this->channelGetById($cid); + $levelno = 0; + + if($channel["pid"]) + { + $levelno = $this->channelGetLevel($channel["pid"])+1; + } + + return $levelno; + } + + /** + * Returns the pathway of a channel which can be used as a clients default channel. + * + * @param integer $cid + * @return string + */ + public function channelGetPathway($cid) + { + $channel = $this->channelGetById($cid); + $pathway = $channel["channel_name"]; + + if($channel["pid"]) + { + $pathway = $this->channelGetPathway($channel["pid"]) . "/" . $channel["channel_name"]; + } + + return $pathway; + } + + /** + * Returns the TeamSpeak3_Node_Channel object matching the given ID. + * + * @param integer $cid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function channelGetById($cid) + { + if(!array_key_exists((string) $cid, $this->channelList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + return $this->channelList[intval((string) $cid)]; + } + + /** + * Returns the TeamSpeak3_Node_Channel object matching the given name. + * + * @param string $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function channelGetByName($name) + { + foreach($this->channelList() as $channel) + { + if($channel["channel_name"] == $name) return $channel; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + /** + * Returns an array filled with TeamSpeak3_Node_Client objects. + * + * @param array $filter + * @return array + */ + public function clientList(array $filter = array()) + { + if($this->clientList === null) + { + $clients = $this->request("clientlist -uid -away -badges -voice -info -times -groups -icon -country -ip")->toAssocArray("clid"); + + $this->clientList = array(); + + foreach($clients as $clid => $client) + { + if($this->getParent()->getExcludeQueryClients() && $client["client_type"]) continue; + + $this->clientList[$clid] = new TeamSpeak3_Node_Client($this, $client); + } + + uasort($this->clientList, array(__CLASS__, "sortClientList")); + + $this->resetNodeList(); + } + + return $this->filterList($this->clientList, $filter); + } + + /** + * Resets the list of clients online. + * + * @return void + */ + public function clientListReset() + { + $this->resetNodeList(); + $this->clientList = null; + } + + /** + * Returns a list of clients matching a given name pattern. + * + * @param string $pattern + * @return array + */ + public function clientFind($pattern) + { + return $this->execute("clientfind", array("pattern" => $pattern))->toAssocArray("clid"); + } + + /** + * Returns a list of client identities known by the virtual server. By default, the server spits out 25 entries + * at once. + * + * @param integer $offset + * @param integer $limit + * @return array + */ + public function clientListDb($offset = null, $limit = null) + { + return $this->execute("clientdblist -count", array("start" => $offset, "duration" => $limit))->toAssocArray("cldbid"); + } + + /** + * Returns the number of client identities known by the virtual server. + * + * @return integer + */ + public function clientCountDb() + { + return current($this->execute("clientdblist -count", array("duration" => 1))->toList("count")); + } + + /** + * Returns a list of properties from the database for the client specified by $cldbid. + * + * @param integer $cldbid + * @return array + */ + public function clientInfoDb($cldbid) + { + return $this->execute("clientdbinfo", array("cldbid" => $cldbid))->toList(); + } + + /** + * Returns a list of client database IDs matching a given pattern. You can either search for a clients + * last known nickname or his unique identity by using the $uid option. + * + * @param string $pattern + * @param boolean $uid + * @return array + */ + public function clientFindDb($pattern, $uid = FALSE) + { + return array_keys($this->execute("clientdbfind", array("pattern" => $pattern, ($uid) ? "-uid" : null))->toAssocArray("cldbid")); + } + + /** + * Returns the number of regular clients online. + * + * @return integer + */ + public function clientCount() + { + if($this->isOffline()) return 0; + + return $this["virtualserver_clientsonline"]-$this["virtualserver_queryclientsonline"]; + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given ID. + * + * @param integer $clid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetById($clid) + { + if(!array_key_exists((string) $clid, $this->clientList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + return $this->clientList[intval((string) $clid)]; + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given name. + * + * @param string $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetByName($name) + { + foreach($this->clientList() as $client) + { + if($client["client_nickname"] == $name) return $client; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given unique identifier. + * + * @param string $uid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetByUid($uid) + { + foreach($this->clientList() as $client) + { + if($client["client_unique_identifier"] == $uid) return $client; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given database ID. + * + * @param integer $dbid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetByDbid($dbid) + { + foreach($this->clientList() as $client) + { + if($client["client_database_id"] == $dbid) return $client; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + /** + * Returns an array containing the last known nickname and the database ID of the client matching + * the unique identifier specified with $cluid. + * + * @param string $cluid + * @return array + */ + public function clientGetNameByUid($cluid) + { + return $this->execute("clientgetnamefromuid", array("cluid" => $cluid))->toList(); + } + + /** + * Returns an array containing a list of active client connections using the unique identifier + * specified with $cluid. + * + * @param string $cluid + * @return array + */ + public function clientGetIdsByUid($cluid) + { + return $this->execute("clientgetids", array("cluid" => $cluid))->toAssocArray("clid"); + } + + /** + * Returns an array containing the last known nickname and the unique identifier of the client + * matching the database ID specified with $cldbid. + * + * @param string $cldbid + * @return array + */ + public function clientGetNameByDbid($cldbid) + { + return $this->execute("clientgetnamefromdbid", array("cldbid" => $cldbid))->toList(); + } + + /** + * Returns an array containing the names and IDs of all server groups the client specified with + * $cldbid is is currently residing in. + * + * @param string $cldbid + * @return array + */ + public function clientGetServerGroupsByDbid($cldbid) + { + return $this->execute("servergroupsbyclientid", array("cldbid" => $cldbid))->toAssocArray("sgid"); + } + + /** + * Moves a client to another channel. + * + * @param integer $clid + * @param integer $cid + * @param string $cpw + * @return void + */ + public function clientMove($clid, $cid, $cpw = null) + { + $this->clientListReset(); + + $this->execute("clientmove", array("clid" => $clid, "cid" => $cid, "cpw" => $cpw)); + + if($clid instanceof TeamSpeak3_Node_Abstract) + { + $clid = $clid->getId(); + } + + if($cid instanceof TeamSpeak3_Node_Abstract) + { + $cid = $cid->getId(); + } + + if(!is_array($clid) && $clid == $this->whoamiGet("client_id")) + { + $this->getParent()->whoamiSet("client_channel_id", $cid); + } + } + + /** + * Kicks one or more clients from their currently joined channel or from the server. + * + * @param integer $clid + * @param integer $reasonid + * @param string $reasonmsg + * @return void + */ + public function clientKick($clid, $reasonid = TeamSpeak3::KICK_CHANNEL, $reasonmsg = null) + { + $this->clientListReset(); + + $this->execute("clientkick", array("clid" => $clid, "reasonid" => $reasonid, "reasonmsg" => $reasonmsg)); + } + + /** + * Sends a poke message to a client. + * + * @param integer $clid + * @param string $msg + * @return void + */ + public function clientPoke($clid, $msg) + { + $this->execute("clientpoke", array("clid" => $clid, "msg" => $msg)); + } + + /** + * Bans the client specified with ID $clid from the server. Please note that this will create two separate + * ban rules for the targeted clients IP address and his unique identifier. + * + * @param integer $clid + * @param integer $timeseconds + * @param string $reason + * @return array + */ + public function clientBan($clid, $timeseconds = null, $reason = null) + { + $this->clientListReset(); + + $bans = $this->execute("banclient", array("clid" => $clid, "time" => $timeseconds, "banreason" => $reason))->toAssocArray("banid"); + + return array_keys($bans); + } + + /** + * Changes the clients properties using given properties. + * + * @param string $cldbid + * @param array $properties + * @return void + */ + public function clientModifyDb($cldbid, array $properties) + { + $properties["cldbid"] = $cldbid; + + $this->execute("clientdbedit", $properties); + } + + /** + * Deletes a clients properties from the database. + * + * @param string $cldbid + * @return void + */ + public function clientDeleteDb($cldbid) + { + $this->execute("clientdbdelete", array("cldbid" => $cldbid)); + } + + /** + * Sets the channel group of a client to the ID specified. + * + * @param integer $cldbid + * @param integer $cid + * @param integer $cgid + * @return void + */ + public function clientSetChannelGroup($cldbid, $cid, $cgid) + { + $this->execute("setclientchannelgroup", array("cldbid" => $cldbid, "cid" => $cid, "cgid" => $cgid)); + } + + /** + * Returns a list of permissions defined for a client. + * + * @param integer $cldbid + * @param boolean $permsid + * @return array + */ + public function clientPermList($cldbid, $permsid = FALSE) + { + $this->clientListReset(); + + return $this->execute("clientpermlist", array("cldbid" => $cldbid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to a client. Multiple permissions can be added by providing + * the three parameters of each permission. + * + * @param integer $cldbid + * @param integer $permid + * @param integer $permvalue + * @param integer $permskip + * @return void + */ + public function clientPermAssign($cldbid, $permid, $permvalue, $permskip = FALSE) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("clientaddperm", array("cldbid" => $cldbid, $permident => $permid, "permvalue" => $permvalue, "permskip" => $permskip)); + } + + /** + * Removes a set of specified permissions from a client. Multiple permissions can be removed at once. + * + * @param integer $cldbid + * @param integer $permid + * @return void + */ + public function clientPermRemove($cldbid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("clientdelperm", array("cldbid" => $cldbid, $permident => $permid)); + } + + /** + * Returns a list of server groups available. + * + * @param filter $filter + * @return array + */ + public function serverGroupList(array $filter = array()) + { + if($this->sgroupList === null) + { + $this->sgroupList = $this->request("servergrouplist")->toAssocArray("sgid"); + + foreach($this->sgroupList as $sgid => $group) + { + $this->sgroupList[$sgid] = new TeamSpeak3_Node_Servergroup($this, $group); + } + + uasort($this->sgroupList, array(__CLASS__, "sortGroupList")); + } + + return $this->filterList($this->sgroupList, $filter); + } + + /** + * Resets the list of server groups. + * + * @return void + */ + public function serverGroupListReset() + { + $this->sgroupList = null; + } + + /** + * Creates a new server group using the name specified with $name and returns its ID. + * + * @param string $name + * @param integer $type + * @return integer + */ + public function serverGroupCreate($name, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + $this->serverGroupListReset(); + + $sgid = $this->execute("servergroupadd", array("name" => $name, "type" => $type))->toList(); + + return $sgid["sgid"]; + } + + /** + * Creates a copy of an existing server group specified by $ssgid and returns the new groups ID. + * + * @param integer $ssgid + * @param string $name + * @param integer $tsgid + * @param integer $type + * @return integer + */ + public function serverGroupCopy($ssgid, $name = null, $tsgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + $this->serverGroupListReset(); + + $sgid = $this->execute("servergroupcopy", array("ssgid" => $ssgid, "tsgid" => $tsgid, "name" => $name, "type" => $type))->toList(); + + if($tsgid && $name) + { + $this->serverGroupRename($tsgid, $name); + } + + return count($sgid) ? $sgid["sgid"] : intval($tsgid); + } + + /** + * Renames the server group specified with $sgid. + * + * @param integer $sgid + * @param string $name + * @return void + */ + public function serverGroupRename($sgid, $name) + { + $this->serverGroupListReset(); + + $this->execute("servergrouprename", array("sgid" => $sgid, "name" => $name)); + } + + /** + * Deletes the server group specified with $sgid. If $force is set to 1, the server group + * will be deleted even if there are clients within. + * + * @param integer $sgid + * @param boolean $force + * @return void + */ + public function serverGroupDelete($sgid, $force = FALSE) + { + $this->serverGroupListReset(); + + $this->execute("servergroupdel", array("sgid" => $sgid, "force" => $force)); + } + + /** + * Returns the TeamSpeak3_Node_Servergroup object matching the given ID. + * + * @param integer $sgid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Servergroup + */ + public function serverGroupGetById($sgid) + { + if(!array_key_exists((string) $sgid, $this->serverGroupList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + return $this->sgroupList[intval((string) $sgid)]; + } + + /** + * Returns the TeamSpeak3_Node_Servergroup object matching the given name. + * + * @param string $name + * @param integer $type + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Servergroup + */ + public function serverGroupGetByName($name, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + foreach($this->serverGroupList() as $group) + { + if($group["name"] == $name && $group["type"] == $type) return $group; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + /** + * Returns a list of permissions assigned to the server group specified. + * + * @param integer $sgid + * @param boolean $permsid + * @return array + */ + public function serverGroupPermList($sgid, $permsid = FALSE) + { + return $this->execute("servergrouppermlist", array("sgid" => $sgid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to the server group specified. Multiple permissions + * can be added by providing the four parameters of each permission in separate arrays. + * + * @param integer $sgid + * @param integer $permid + * @param integer $permvalue + * @param integer $permnegated + * @param integer $permskip + * @return void + */ + public function serverGroupPermAssign($sgid, $permid, $permvalue, $permnegated = FALSE, $permskip = FALSE) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("servergroupaddperm", array("sgid" => $sgid, $permident => $permid, "permvalue" => $permvalue, "permnegated" => $permnegated, "permskip" => $permskip)); + } + + /** + * Removes a set of specified permissions from the server group specified with $sgid. Multiple + * permissions can be removed at once. + * + * @param integer $sgid + * @param integer $permid + * @return void + */ + public function serverGroupPermRemove($sgid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("servergroupdelperm", array("sgid" => $sgid, $permident => $permid)); + } + + /** + * Returns a list of clients assigned to the server group specified. + * + * @param integer $sgid + * @return array + */ + public function serverGroupClientList($sgid) + { + if($this["virtualserver_default_server_group"] == $sgid) + { + return array(); + } + + return $this->execute("servergroupclientlist", array("sgid" => $sgid, "-names"))->toAssocArray("cldbid"); + } + + /** + * Adds a client to the server group specified. Please note that a client cannot be + * added to default groups or template groups. + * + * @param integer $sgid + * @param integer $cldbid + * @return void + */ + public function serverGroupClientAdd($sgid, $cldbid) + { + $this->clientListReset(); + + $this->execute("servergroupaddclient", array("sgid" => $sgid, "cldbid" => $cldbid)); + } + + /** + * Removes a client from the server group specified. + * + * @param integer $sgid + * @param integer $cldbid + * @return void + */ + public function serverGroupClientDel($sgid, $cldbid) + { + $this->execute("servergroupdelclient", array("sgid" => $sgid, "cldbid" => $cldbid)); + } + + /** + * Returns an ordered array of regular server groups available based on a pre-defined + * set of rules. + * + * @return array + */ + public function serverGroupGetProfiles() + { + $profiles = array(); + + foreach($this->serverGroupList() as $sgid => $sgroup) + { + if($sgroup["type"] != TeamSpeak3::GROUP_DBTYPE_REGULAR) continue; + + $profiles[$sgid] = array( + "b_permission_modify_power_ignore" => 0, + "i_group_needed_member_add_power" => 0, + "i_group_member_add_power" => 0, + "i_group_needed_member_remove_power" => 0, + "i_group_member_remove_power" => 0, + "i_needed_modify_power_count" => 0, + "i_needed_modify_power_total" => 0, + "i_permission_modify_power" => 0, + "i_group_needed_modify_power" => 0, + "i_group_modify_power" => 0, + "i_client_needed_modify_power" => 0, + "i_client_modify_power" => 0, + "b_virtualserver_servergroup_create" => 0, + "b_virtualserver_servergroup_delete" => 0, + "b_client_ignore_bans" => 0, + "b_client_ignore_antiflood" => 0, + "b_group_is_permanent" => 0, + "i_client_needed_ban_power" => 0, + "i_client_needed_kick_power" => 0, + "i_client_needed_move_power" => 0, + "i_client_talk_power" => 0, + "__sgid" => $sgid, + "__name" => $sgroup->toString(), + "__node" => $sgroup, + ); + + try + { + $perms = $this->serverGroupPermList($sgid, TRUE); + $grant = isset($perms["i_permission_modify_power"]) ? $perms["i_permission_modify_power"]["permvalue"] : null; + } + catch(TeamSpeak3_Adapter_ServerQuery_Exception $e) + { + /* ERROR_database_empty_result */ + if($e->getCode() != 0x501) throw $e; + + $perms = array(); + $grant = null; + } + + foreach($perms as $permsid => $perm) + { + if(in_array($permsid, array_keys($profiles[$sgid]))) + { + $profiles[$sgid][$permsid] = $perm["permvalue"]; + } + elseif(TeamSpeak3_Helper_String::factory($permsid)->startsWith("i_needed_modify_power_")) + { + if(!$grant || $perm["permvalue"] > $grant) continue; + + $profiles[$sgid]["i_needed_modify_power_total"] = $profiles[$sgid]["i_needed_modify_power_total"]+$perm["permvalue"]; + $profiles[$sgid]["i_needed_modify_power_count"]++; + } + } + } + + array_multisort($profiles, SORT_DESC); + + return $profiles; + } + + /** + * Tries to identify the post powerful/weakest server group on the virtual server and returns + * the ID. + * + * @param integer $mode + * @return TeamSpeak3_Node_Servergroup + */ + public function serverGroupIdentify($mode = TeamSpeak3::GROUP_IDENTIFIY_STRONGEST) + { + $profiles = $this->serverGroupGetProfiles(); + + $best_guess_profile = ($mode == TeamSpeak3::GROUP_IDENTIFIY_STRONGEST) ? array_shift($profiles) : array_pop($profiles); + + return $this->serverGroupGetById($best_guess_profile["__sgid"]); + } + + /** + * Returns a list of channel groups available. + * + * @param array $filter + * @return array + */ + public function channelGroupList(array $filter = array()) + { + if($this->cgroupList === null) + { + $this->cgroupList = $this->request("channelgrouplist")->toAssocArray("cgid"); + + foreach($this->cgroupList as $cgid => $group) + { + $this->cgroupList[$cgid] = new TeamSpeak3_Node_Channelgroup($this, $group); + } + + uasort($this->cgroupList, array(__CLASS__, "sortGroupList")); + } + + return $this->filterList($this->cgroupList, $filter); + } + + /** + * Resets the list of channel groups. + * + * @return void + */ + public function channelGroupListReset() + { + $this->cgroupList = null; + } + + /** + * Creates a new channel group using the name specified with $name and returns its ID. + * + * @param string $name + * @param integer $type + * @return integer + */ + public function channelGroupCreate($name, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + $this->channelGroupListReset(); + + $cgid = $this->execute("channelgroupadd", array("name" => $name, "type" => $type))->toList(); + + return $cgid["cgid"]; + } + + /** + * Creates a copy of an existing channel group specified by $scgid and returns the new groups ID. + * + * @param integer $scgid + * @param string $name + * @param integer $tcgid + * @param integer $type + * @return integer + */ + public function channelGroupCopy($scgid, $name = null, $tcgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + $this->channelGroupListReset(); + + $cgid = $this->execute("channelgroupcopy", array("scgid" => $scgid, "tcgid" => $tcgid, "name" => $name, "type" => $type))->toList(); + + if($tcgid && $name) + { + $this->channelGroupRename($tcgid, $name); + } + + return count($cgid) ? $cgid["cgid"] : intval($tcgid); + } + + /** + * Renames the channel group specified with $cgid. + * + * @param integer $cgid + * @param string $name + * @return void + */ + public function channelGroupRename($cgid, $name) + { + $this->channelGroupListReset(); + + $this->execute("channelgrouprename", array("cgid" => $cgid, "name" => $name)); + } + + /** + * Deletes the channel group specified with $cgid. If $force is set to 1, the channel group + * will be deleted even if there are clients within. + * + * @param integer $sgid + * @param boolean $force + * @return void + */ + public function channelGroupDelete($cgid, $force = FALSE) + { + $this->channelGroupListReset(); + + $this->execute("channelgroupdel", array("cgid" => $cgid, "force" => $force)); + } + + /** + * Returns the TeamSpeak3_Node_Channelgroup object matching the given ID. + * + * @param integer $cgid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channelgroup + */ + public function channelGroupGetById($cgid) + { + if(!array_key_exists((string) $cgid, $this->channelGroupList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + return $this->cgroupList[intval((string) $cgid)]; + } + + /** + * Returns the TeamSpeak3_Node_Channelgroup object matching the given name. + * + * @param string $name + * @param integer $type + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channelgroup + */ + public function channelGroupGetByName($name, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + foreach($this->channelGroupList() as $group) + { + if($group["name"] == $name && $group["type"] == $type) return $group; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + /** + * Returns a list of permissions assigned to the channel group specified. + * + * @param integer $cgid + * @param boolean $permsid + * @return array + */ + public function channelGroupPermList($cgid, $permsid = FALSE) + { + return $this->execute("channelgrouppermlist", array("cgid" => $cgid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to the channel group specified. Multiple permissions + * can be added by providing the two parameters of each permission in separate arrays. + * + * @param integer $cgid + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function channelGroupPermAssign($cgid, $permid, $permvalue) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channelgroupaddperm", array("cgid" => $cgid, $permident => $permid, "permvalue" => $permvalue)); + } + + /** + * Removes a set of specified permissions from the channel group specified with $cgid. Multiple + * permissions can be removed at once. + * + * @param integer $cgid + * @param integer $permid + * @return void + */ + public function channelGroupPermRemove($cgid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channelgroupdelperm", array("cgid" => $cgid, $permident => $permid)); + } + + /** + * Returns all the client and/or channel IDs currently assigned to channel groups. All three + * parameters are optional so you're free to choose the most suitable combination for your + * requirements. + * + * @param integer $cgid + * @param integer $cid + * @param integer $cldbid + * @return array + */ + public function channelGroupClientList($cgid = null, $cid = null, $cldbid = null) + { + if($this["virtualserver_default_channel_group"] == $cgid) + { + return array(); + } + + return $this->execute("channelgroupclientlist", array("cgid" => $cgid, "cid" => $cid, "cldbid" => $cldbid))->toArray(); + } + + /** + * Restores the default permission settings on the virtual server and returns a new initial + * administrator privilege key. + * + * @return TeamSpeak3_Helper_String + */ + public function permReset() + { + $token = $this->request("permreset")->toList(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyTokencreated", $this, $token["token"]); + + return $token["token"]; + } + + /** + * Removes any assignment of the permission specified with $permid on the selected virtual server + * and returns the number of removed assignments on success. + * + * @param integer $permid + * @return integer + */ + public function permRemoveAny($permid) + { + $assignments = $this->permissionFind($permid); + + foreach($assignments as $assignment) + { + switch($assignment["t"]) + { + case TeamSpeak3::PERM_TYPE_SERVERGROUP: + $this->serverGroupPermRemove($assignment["id1"], $assignment["p"]); + break; + + case TeamSpeak3::PERM_TYPE_CLIENT: + $this->clientPermRemove($assignment["id2"], $assignment["p"]); + break; + + case TeamSpeak3::PERM_TYPE_CHANNEL: + $this->channelPermRemove($assignment["id2"], $assignment["p"]); + break; + + case TeamSpeak3::PERM_TYPE_CHANNELGROUP: + $this->channelGroupPermRemove($assignment["id1"], $assignment["p"]); + break; + + case TeamSpeak3::PERM_TYPE_CHANNELCLIENT: + $this->channelClientPermRemove($assignment["id2"], $assignment["id1"], $assignment["p"]); + break; + + default: + throw new TeamSpeak3_Adapter_ServerQuery_Exception("convert error", 0x604); + } + } + + return count($assignments); + } + + /** + * Initializes a file transfer upload. $clientftfid is an arbitrary ID to identify the file transfer on client-side. + * + * @param integer $clientftfid + * @param integer $cid + * @param string $name + * @param integer $size + * @param string $cpw + * @param boolean $overwrite + * @param boolean $resume + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return array + */ + public function transferInitUpload($clientftfid, $cid, $name, $size, $cpw = "", $overwrite = FALSE, $resume = FALSE) + { + $upload = $this->execute("ftinitupload", array("clientftfid" => $clientftfid, "cid" => $cid, "name" => $name, "cpw" => $cpw, "size" => $size, "overwrite" => $overwrite, "resume" => $resume))->toList(); + + if(array_key_exists("status", $upload) && $upload["status"] != 0x00) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception($upload["msg"], $upload["status"]); + } + + $upload["cid"] = $cid; + $upload["file"] = $name; + + if(!array_key_exists("ip", $upload) || $upload["ip"]->startsWith("0.0.0.0")) + { + $upload["ip"] = $this->getParent()->getAdapterHost(); + $upload["host"] = $upload["ip"]; + } + else + { + $upload["ip"] = $upload["ip"]->section(","); + $upload["host"] = $upload["ip"]; + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferUploadInit", $upload["ftkey"], $upload); + + return $upload; + } + + /** + * Initializes a file transfer download. $clientftfid is an arbitrary ID to identify the file transfer on client-side. + * + * @param integer $clientftfid + * @param integer $cid + * @param string $name + * @param string $cpw + * @param integer $seekpos + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return array + */ + public function transferInitDownload($clientftfid, $cid, $name, $cpw = "", $seekpos = 0) + { + $download = $this->execute("ftinitdownload", array("clientftfid" => $clientftfid, "cid" => $cid, "name" => $name, "cpw" => $cpw, "seekpos" => $seekpos))->toList(); + + if(array_key_exists("status", $download) && $download["status"] != 0x00) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception($download["msg"], $download["status"]); + } + + $download["cid"] = $cid; + $download["file"] = $name; + + if(!array_key_exists("ip", $download) || $download["ip"]->startsWith("0.0.0.0")) + { + $download["ip"] = $this->getParent()->getAdapterHost(); + $download["host"] = $download["ip"]; + } + else + { + $download["ip"] = $download["ip"]->section(","); + $download["host"] = $download["ip"]; + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferDownloadInit", $download["ftkey"], $download); + + return $download; + } + + /** + * Displays a list of running file transfers on the selected virtual server. The output contains the path to + * which a file is uploaded to, the current transfer rate in bytes per second, etc. + * + * @return array + */ + public function transferList() + { + return $this->request("ftlist")->toAssocArray("serverftfid"); + } + + /** + * Stops the running file transfer with server-side ID $serverftfid. + * + * @param integer $serverftfid + * @param boolean $delete + * @return void + */ + public function transferStop($serverftfid, $delete = FALSE) + { + $this->execute("ftstop", array("serverftfid" => $serverftfid, "delete" => $delete)); + } + + /** + * Downloads and returns the servers icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("virtualserver_icon_id") || $this["virtualserver_icon_id"] == 0) return; + + $download = $this->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("virtualserver_icon_id")); + $transfer = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * Uploads a given icon file content to the server and returns the ID of the icon. + * + * @param string $data + * @return integer + */ + public function iconUpload($data) + { + $crc = crc32($data); + $size = strlen($data); + + $upload = $this->transferInitUpload(rand(0x0000, 0xFFFF), 0, "/icon_" . $crc, $size); + $transfer = TeamSpeak3::factory("filetransfer://" . (strstr($upload["host"], ":") !== FALSE ? "[" . $upload["host"] . "]" : $upload["host"]) . ":" . $upload["port"]); + + $transfer->upload($upload["ftkey"], $upload["seekpos"], $data); + + return $crc; + } + + /** + * Changes the virtual server configuration using given properties. + * + * @param array $properties + * @return void + */ + public function modify(array $properties) + { + $this->execute("serveredit", $properties); + $this->resetNodeInfo(); + } + + /** + * Sends a text message to all clients on the virtual server. + * + * @param string $msg + * @return void + */ + public function message($msg) + { + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $this->getId(), "targetmode" => TeamSpeak3::TEXTMSG_SERVER)); + } + + /** + * Returns a list of offline messages you've received. The output contains the senders unique identifier, + * the messages subject, etc. + * + * @return array + */ + public function messageList() + { + return $this->request("messagelist")->toAssocArray("msgid"); + } + + /** + * Sends an offline message to the client specified by $cluid. + * + * @param string $cluid + * @param string $subject + * @param string $message + * @return void + */ + public function messageCreate($cluid, $subject, $message) + { + $this->execute("messageadd", array("cluid" => $cluid, "subject" => $subject, "message" => $message)); + } + + /** + * Deletes an existing offline message with ID $msgid from your inbox. + * + * @param integer $msgid + * @return void + */ + public function messageDelete($msgid) + { + $this->execute("messagedel", array("msgid" => $msgid)); + } + + /** + * Returns an existing offline message with ID $msgid from your inbox. + * + * @param integer $msgid + * @param boolean $flag_read + * @return array + */ + public function messageRead($msgid, $flag_read = TRUE) + { + $msg = $this->execute("messageget", array("msgid" => $msgid))->toList(); + + if($flag_read) + { + $this->execute("messageget", array("msgid" => $msgid, "flag" => $flag_read)); + } + + return $msg; + } + + /** + * Creates and returns snapshot data for the selected virtual server. + * + * @param string $mode + * @return string + */ + public function snapshotCreate($mode = TeamSpeak3::SNAPSHOT_STRING) + { + $snapshot = $this->request("serversnapshotcreate")->toString(FALSE); + + switch($mode) + { + case TeamSpeak3::SNAPSHOT_BASE64: + return $snapshot->toBase64(); + break; + + case TeamSpeak3::SNAPSHOT_HEXDEC: + return $snapshot->toHex(); + break; + + default: + return (string) $snapshot; + break; + } + } + + /** + * Deploys snapshot data on the selected virtual server. If no virtual server is selected (ID 0), + * the data will be used to create a new virtual server from scratch. + * + * @param string $data + * @param string $mode + * @return array + */ + public function snapshotDeploy($data, $mode = TeamSpeak3::SNAPSHOT_STRING) + { + switch($mode) + { + case TeamSpeak3::SNAPSHOT_BASE64: + $data = TeamSpeak3_Helper_String::fromBase64($data); + break; + + case TeamSpeak3::SNAPSHOT_HEXDEC: + $data = TeamSpeak3_Helper_String::fromHex($data); + break; + + default: + $data = TeamSpeak3_Helper_String::factory($data); + break; + } + + $detail = $this->request("serversnapshotdeploy " . $data)->toList(); + + if(array_key_exists("sid", $detail)) + { + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServercreated", $this->getParent(), $detail["sid"]); + } + + return $detail; + } + + /** + * Registers for a specified category of events on a virtual server to receive notification + * messages. Depending on the notifications you've registered for, the server will send you + * a message on every event. + * + * @param string $event + * @param integer $id + * @return void + */ + public function notifyRegister($event, $id = 0) + { + $this->execute("servernotifyregister", array("event" => $event, "id" => $id)); + } + + /** + * Unregisters all events previously registered with servernotifyregister so you will no + * longer receive notification messages. + * + * @return void + */ + public function notifyUnregister() + { + $this->request("servernotifyunregister"); + } + + /** + * Alias for privilegeKeyList(). + * + * @deprecated + */ + public function tokenList($translate = FALSE) + { + return $this->privilegeKeyList(); + } + + /** + * Returns a list of privilege keys (tokens) available. If $resolve is set to TRUE the values + * of token_id1 and token_id2 will be translated into the appropriate group and/or channel + * names. + * + * @param boolean $resolve + * @return array + */ + public function privilegeKeyList($resolve = FALSE) + { + $tokens = $this->request("privilegekeylist")->toAssocArray("token"); + + if($resolve) + { + foreach($tokens as $token => $array) + { + $func = $array["token_type"] ? "channelGroupGetById" : "serverGroupGetById"; + + try + { + $tokens[$token]["token_id1"] = $this->$func($array["token_id1"])->name; + } + catch(Exception $e) + { + /* ERROR_channel_invalid_id */ + if($e->getCode() != 0xA00) throw $e; + } + + try + { + if($array["token_type"]) $tokens[$token]["token_id2"] = $this->channelGetById($array["token_id2"])->getPathway(); + } + catch(Exception $e) + { + /* ERROR_permission_invalid_group_id */ + if($e->getCode() != 0x300) throw $e; + } + } + } + + return $tokens; + } + + /** + * Alias for privilegeKeyCreate(). + * + * @deprecated + */ + public function tokenCreate($type = TeamSpeak3::TOKEN_SERVERGROUP, $id1, $id2 = 0, $description = null, $customset = null) + { + return $this->privilegeKeyCreate($type, $id1, $id2, $description, $customset); + } + + /** + * Creates a new privilege key (token) and returns the key. + * + * @param integer $type + * @param integer $id1 + * @param integer $id2 + * @param string $description + * @param string $customset + * @return TeamSpeak3_Helper_String + */ + public function privilegeKeyCreate($type = TeamSpeak3::TOKEN_SERVERGROUP, $id1, $id2 = 0, $description = null, $customset = null) + { + $token = $this->execute("privilegekeyadd", array("tokentype" => $type, "tokenid1" => $id1, "tokenid2" => $id2, "tokendescription" => $description, "tokencustomset" => $customset))->toList(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyTokencreated", $this, $token["token"]); + + return $token["token"]; + } + + /** + * Alias for privilegeKeyDelete(). + * + * @deprecated + */ + public function tokenDelete($token) + { + $this->privilegeKeyDelete($token); + } + + /** + * Deletes a token specified by key $token. + * + * @param string $token + * @return void + */ + public function privilegeKeyDelete($token) + { + $this->execute("privilegekeydelete", array("token" => $token)); + } + + /** + * Alias for privilegeKeyUse(). + * + * @deprecated + */ + public function tokenUse($token) + { + $this->privilegeKeyUse($token); + } + + /** + * Use a token key gain access to a server or channel group. Please note that the server will + * automatically delete the token after it has been used. + * + * @param string $token + * @return void + */ + public function privilegeKeyUse($token) + { + $this->execute("privilegekeyuse", array("token" => $token)); + } + + /** + * Returns a list of custom client properties specified by $ident. + * + * @param string $ident + * @param string $pattern + * @return array + */ + public function customSearch($ident, $pattern = "%") + { + return $this->execute("customsearch", array("ident" => $ident, "pattern" => $pattern))->toArray(); + } + + /** + * Returns a list of custom properties for the client specified by $cldbid. + * + * @param integer $cldbid + * @return array + */ + public function customInfo($cldbid) + { + return $this->execute("custominfo", array("cldbid" => $cldbid))->toArray(); + } + + /** + * Returns a list of active bans on the selected virtual server. + * + * @return array + */ + public function banList() + { + return $this->request("banlist")->toAssocArray("banid"); + } + + /** + * Deletes all active ban rules from the server. + * + * @return void + */ + public function banListClear() + { + $this->request("bandelall"); + } + + /** + * Adds a new ban rule on the selected virtual server. All parameters are optional but at least one + * of the following rules must be set: ip, name, or uid. + * + * @param array $rules + * @param integer $timeseconds + * @param string $reason + * @return integer + */ + public function banCreate(array $rules, $timeseconds = null, $reason = null) + { + $rules["time"] = $timeseconds; + $rules["banreason"] = $reason; + + $banid = $this->execute("banadd", $rules)->toList(); + + return $banid["banid"]; + } + + /** + * Deletes the specified ban rule from the server. + * + * @param integer $banid + * @return void + */ + public function banDelete($banid) + { + $this->execute("bandel", array("banid" => $banid)); + } + + /** + * Returns a list of complaints on the selected virtual server. If $tcldbid is specified, only + * complaints about the targeted client will be shown. + * + * @param integer $tcldbid + * @return array + */ + public function complaintList($tcldbid = null) + { + return $this->execute("complainlist", array("tcldbid" => $tcldbid))->toArray(); + } + + /** + * Deletes all active complaints about the client with database ID $tcldbid from the server. + * + * @param integer $tcldbid + * @return void + */ + public function complaintListClear($tcldbid) + { + $this->execute("complaindelall", array("tcldbid" => $tcldbid)); + } + + /** + * Submits a complaint about the client with database ID $tcldbid to the server. + * + * @param integer $tcldbid + * @param string $message + * @return void + */ + public function complaintCreate($tcldbid, $message) + { + $this->execute("complainadd", array("tcldbid" => $tcldbid, "message" => $message)); + } + + /** + * Deletes the complaint about the client with ID $tcldbid submitted by the client with ID $fcldbid from the server. + * + * @param integer $tcldbid + * @param integer $fcldbid + * @return void + */ + public function complaintDelete($tcldbid, $fcldbid) + { + $this->execute("complaindel", array("tcldbid" => $tcldbid, "fcldbid" => $fcldbid)); + } + + /** + * Returns a list of temporary server passwords. + * + * @param boolean $resolve + * @return array + */ + public function tempPasswordList($resolve = FALSE) + { + $passwords = $this->request("servertemppasswordlist")->toAssocArray("pw_clear"); + + if($resolve) + { + foreach($passwords as $password => $array) + { + try + { + $channel = $this->channelGetById($array["tcid"]); + + $passwords[$password]["tcname"] = $channel->toString(); + $passwords[$password]["tcpath"] = $channel->getPathway(); + } + catch(Exception $e) + { + /* ERROR_channel_invalid_id */ + if($e->getCode() != 0xA00) throw $e; + } + } + } + + return $passwords; + } + + /** + * Sets a new temporary server password specified with $pw. The temporary password will be + * valid for the number of seconds specified with $duration. The client connecting with this + * password will automatically join the channel specified with $tcid. If tcid is set to 0, + * the client will join the default channel. + * + * @param string $pw + * @param integer $duration + * @param integer $tcid + * @param string $tcpw + * @param string $desc + * @return void + */ + public function tempPasswordCreate($pw, $duration, $tcid = 0, $tcpw = "", $desc = "") + { + $this->execute("servertemppasswordadd", array("pw" => $pw, "duration" => $duration, "tcid" => $tcid, "tcpw" => $tcpw, "desc" => $desc)); + } + + /** + * Deletes the temporary server password specified with $pw. + * + * @param string $pw + * @return void + */ + public function tempPasswordDelete($pw) + { + $this->execute("servertemppassworddel", array("pw" => $pw)); + } + + /** + * Displays a specified number of entries (1-100) from the servers log. + * + * @param integer $lines + * @param integer $begin_pos + * @param boolean $reverse + * @param boolean $instance + * @return array + */ + public function logView($lines = 30, $begin_pos = null, $reverse = null, $instance = null) + { + return $this->execute("logview", array("lines" => $lines, "begin_pos" => $begin_pos, "instance" => $instance, "reverse" => $reverse))->toArray(); + } + + /** + * Writes a custom entry into the virtual server log. + * + * @param string $logmsg + * @param integer $loglevel + * @return void + */ + public function logAdd($logmsg, $loglevel = TeamSpeak3::LOGLEVEL_INFO) + { + $this->execute("logadd", array("logmsg" => $logmsg, "loglevel" => $loglevel)); + } + + /** + * Returns detailed connection information of the virtual server. + * + * @return array + */ + public function connectionInfo() + { + return $this->request("serverrequestconnectioninfo")->toList(); + } + + /** + * Deletes the virtual server. + * + * @return void + */ + public function delete() + { + $this->getParent()->serverDelete($this->getId()); + + unset($this); + } + + /** + * Starts the virtual server. + * + * @return void + */ + public function start() + { + $this->getParent()->serverStart($this->getId()); + } + + /** + * Stops the virtual server. + * + * @return void + */ + public function stop() + { + $this->getParent()->serverStop($this->getId()); + } + + /** + * Sends a plugin command to all clients connected to the server. + * + * @param string $plugin + * @param string $data + * @return void + */ + public function sendPluginCmd($plugin, $data) + { + $this->execute("plugincmd", array("name" => $plugin, "data" => $data, "targetmode" => TeamSpeak3::PLUGINCMD_SERVER)); + } + + /** + * Changes the properties of your own client connection. + * + * @param array $properties + * @return void + */ + public function selfUpdate(array $properties) + { + $this->execute("clientupdate", $properties); + + foreach($properties as $ident => $value) + { + $this->whoamiSet($ident, $value); + } + } + + /** + * Updates your own ServerQuery login credentials using a specified username. The password + * will be auto-generated. + * + * @param string $username + * @return TeamSpeak3_Helper_String + */ + public function selfUpdateLogin($username) + { + $password = $this->execute("clientsetserverquerylogin", array("client_login_name" => $username))->toList(); + + return $password["client_login_password"]; + } + + /** + * Returns an array containing the permission overview of your own client. + * + * @return array + */ + public function selfPermOverview() + { + return $this->execute("permoverview", array("cldbid" => $this->whoamiGet("client_database_id"), "cid" => $this->whoamiGet("client_channel_id"), "permid" => 0))->toArray(); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + + foreach($this->channelList() as $channel) + { + if($channel["pid"] == 0) + { + $this->nodeList[] = $channel; + } + } + } + + /** + * @ignore + */ + protected function fetchNodeInfo() + { + $this->nodeInfo = array_merge($this->nodeInfo, $this->request("serverinfo")->toList()); + } + + /** + * Internal callback funtion for sorting of client objects. + * + * @param TeamSpeak3_Node_Client $a + * @param TeamSpeak3_Node_Client $b + * @return integer + */ + protected static function sortClientList(TeamSpeak3_Node_Client $a, TeamSpeak3_Node_Client $b) + { + if(get_class($a) != get_class($b)) + { + return 0; + + /* workaround for PHP bug #50688 */ + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + if(!$a instanceof TeamSpeak3_Node_Client) + { + return 0; + + /* workaround for PHP bug #50688 */ + throw new TeamSpeak3_Adapter_ServerQuery_Exception("convert error", 0x604); + } + + if($a->getProperty("client_talk_power", 0) != $b->getProperty("client_talk_power", 0)) + { + return ($a->getProperty("client_talk_power", 0) > $b->getProperty("client_talk_power", 0)) ? -1 : 1; + } + + if($a->getProperty("client_is_talker", 0) != $b->getProperty("client_is_talker", 0)) + { + return ($a->getProperty("client_is_talker", 0) > $b->getProperty("client_is_talker", 0)) ? -1 : 1; + } + + return strcmp(strtolower($a["client_nickname"]), strtolower($b["client_nickname"])); + } + + /** + * Internal callback funtion for sorting of group objects. + * + * @param TeamSpeak3_Node_Abstract $a + * @param TeamSpeak3_Node_Abstract $b + * @return integer + */ + protected static function sortGroupList(TeamSpeak3_Node_Abstract $a, TeamSpeak3_Node_Abstract $b) + { + if(get_class($a) != get_class($b)) + { + return 0; + + /* workaround for PHP bug #50688 */ + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + if(!$a instanceof TeamSpeak3_Node_Servergroup && !$a instanceof TeamSpeak3_Node_Channelgroup) + { + return 0; + + /* workaround for PHP bug #50688 */ + throw new TeamSpeak3_Adapter_ServerQuery_Exception("convert error", 0x604); + } + + if($a->getProperty("sortid", 0) != $b->getProperty("sortid", 0) && $a->getProperty("sortid", 0) != 0 && $b->getProperty("sortid", 0) != 0) + { + return ($a->getProperty("sortid", 0) < $b->getProperty("sortid", 0)) ? -1 : 1; + } + + return ($a->getId() < $b->getId()) ? -1 : 1; + } + +/** + * Internal callback funtion for sorting of file list items. + * + * @param array $a + * @param array $b + * @return integer + */ + protected static function sortFileList(array $a, array $b) + { + if(!array_key_exists("src", $a) || !array_key_exists("src", $b) || !array_key_exists("type", $a) || !array_key_exists("type", $b)) + { + return 0; + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + if($a["type"] != $b["type"]) + { + return ($a["type"] < $b["type"]) ? -1 : 1; + } + + return strcmp(strtolower($a["src"]), strtolower($b["src"])); + } + + /** + * Returns TRUE if the virtual server is online. + * + * @return boolean + */ + public function isOnline() + { + return ($this["virtualserver_status"] == "online") ? TRUE : FALSE; + } + + /** + * Returns TRUE if the virtual server is offline. + * + * @return boolean + */ + public function isOffline() + { + return ($this["virtualserver_status"] == "offline") ? TRUE : FALSE; + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_s" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + if($this["virtualserver_clientsonline"]-$this["virtualserver_queryclientsonline"] >= $this["virtualserver_maxclients"]) + { + return "server_full"; + } + elseif($this["virtualserver_flag_password"]) + { + return "server_pass"; + } + else + { + return "server_open"; + } + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "$"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["virtualserver_name"]; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Node/Servergroup.php b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Servergroup.php new file mode 100644 index 0000000..d836b34 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Node/Servergroup.php @@ -0,0 +1,300 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Servergroup + * @brief Class describing a TeamSpeak 3 server group and all it's parameters. + */ +class TeamSpeak3_Node_Servergroup extends TeamSpeak3_Node_Abstract +{ + /** + * The TeamSpeak3_Node_Servergroup constructor. + * + * @param TeamSpeak3_Node_Server $server + * @param array $info + * @param string $index + * @throws TeamSpeak3_Node_Exception + * @return TeamSpeak3_Node_Servergroup + */ + public function __construct(TeamSpeak3_Node_Server $server, array $info, $index = "sgid") + { + $this->parent = $server; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Node_Exception("invalid groupID", 0xA00); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Renames the server group specified. + * + * @param string $name + * @return void + */ + public function rename($name) + { + $this->getParent()->serverGroupRename($this->getId(), $name); + } + + /** + * Deletes the server group. If $force is set to 1, the server group will be + * deleted even if there are clients within. + * + * @param boolean $force + * @return void + */ + public function delete($force = FALSE) + { + $this->getParent()->serverGroupDelete($this->getId(), $force); + + unset($this); + } + + /** + * Creates a copy of the server group and returns the new groups ID. + * + * @param string $name + * @param integer $tsgid + * @param integer $type + * @return integer + */ + public function copy($name = null, $tsgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + return $this->getParent()->serverGroupCopy($this->getId(), $name, $tsgid, $type); + } + + /** + * Returns a list of permissions assigned to the server group. + * + * @param boolean $permsid + * @return array + */ + public function permList($permsid = FALSE) + { + return $this->getParent()->serverGroupPermList($this->getId(), $permsid); + } + + /** + * Adds a set of specified permissions to the server group. Multiple permissions + * can be added by providing the four parameters of each permission in separate arrays. + * + * @param integer $permid + * @param integer $permvalue + * @param integer $permnegated + * @param integer $permskip + * @return void + */ + public function permAssign($permid, $permvalue, $permnegated = FALSE, $permskip = FALSE) + { + $this->getParent()->serverGroupPermAssign($this->getId(), $permid, $permvalue, $permnegated, $permskip); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permAssignByName($permname, $permvalue, $permnegated = FALSE, $permskip = FALSE) + { + $this->permAssign($permname, $permvalue, $permnegated, $permskip); + } + + /** + * Removes a set of specified permissions from the server group. Multiple + * permissions can be removed at once. + * + * @param integer $permid + * @return void + */ + public function permRemove($permid) + { + $this->getParent()->serverGroupPermRemove($this->getId(), $permid); + } + + /** + * Alias for permRemove(). + * + * @deprecated + */ + public function permRemoveByName($permname) + { + $this->permRemove($permname); + } + + /** + * Returns a list of clients assigned to the server group specified. + * + * @return array + */ + public function clientList() + { + return $this->getParent()->serverGroupClientList($this->getId()); + } + + /** + * Adds a client to the server group specified. Please note that a client cannot be + * added to default groups or template groups. + * + * @param integer $cldbid + * @return void + */ + public function clientAdd($cldbid) + { + $this->getParent()->serverGroupClientAdd($this->getId(), $cldbid); + } + + /** + * Removes a client from the server group. + * + * @param integer $cldbid + * @return void + */ + public function clientDel($cldbid) + { + $this->getParent()->serverGroupClientDel($this->getId(), $cldbid); + } + + /** + * Alias for privilegeKeyCreate(). + * + * @deprecated + */ + public function tokenCreate($description = null, $customset = null) + { + return $this->privilegeKeyCreate($description, $customset); + } + + /** + * Creates a new privilege key (token) for the server group and returns the key. + * + * @param string $description + * @param string $customset + * @return TeamSpeak3_Helper_String + */ + public function privilegeKeyCreate($description = null, $customset = null) + { + return $this->getParent()->privilegeKeyCreate(TeamSpeak3::TOKEN_SERVERGROUP, $this->getId(), 0, $description, $customset); + } + + /** + * Sends a text message to all clients residing in the server group on the virtual server. + * + * @param string $msg + * @return void + */ + public function message($msg) + { + foreach($this as $client) + { + try + { + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $client, "targetmode" => TeamSpeak3::TEXTMSG_CLIENT)); + } + catch(TeamSpeak3_Adapter_ServerQuery_Exception $e) + { + /* ERROR_client_invalid_id */ + if($e->getCode() != 0x0200) throw $e; + } + } + } + + /** + * Downloads and returns the server groups icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("iconid") || $this["iconid"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("iconid")); + $transfer = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + + foreach($this->getParent()->clientList() as $client) + { + if(in_array($this->getId(), explode(",", $client["client_servergroups"]))) + { + $this->nodeList[] = $client; + } + } + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_sg" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + return "group_server"; + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "%"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["name"]; + } +} + diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/TeamSpeak3.php b/lib/ts3phpframework/libraries/TeamSpeak3/TeamSpeak3.php new file mode 100644 index 0000000..deed54e --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/TeamSpeak3.php @@ -0,0 +1,974 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3 + * @brief Factory class all for TeamSpeak 3 PHP Framework objects. + */ +class TeamSpeak3 +{ + /** + * TeamSpeak 3 protocol welcome message. + */ + const READY = "TS3"; + + /** + * TeamSpeak 3 protocol greeting message prefix. + */ + const GREET = "Welcome"; + + /** + * TeamSpeak 3 protocol error message prefix. + */ + const ERROR = "error"; + + /** + * TeamSpeak 3 protocol event message prefix. + */ + const EVENT = "notify"; + + /** + * TeamSpeak 3 protocol server connection handler ID prefix. + */ + const SCHID = "selected"; + + /** + * TeamSpeak 3 PHP Framework version. + */ + const LIB_VERSION = "1.1.24"; + + /*@ + * TeamSpeak 3 protocol separators. + */ + const SEPARATOR_LINE = "\n"; //!< protocol line separator + const SEPARATOR_LIST = "|"; //!< protocol list separator + const SEPARATOR_CELL = " "; //!< protocol cell separator + const SEPARATOR_PAIR = "="; //!< protocol pair separator + + /*@ + * TeamSpeak 3 log levels. + */ + const LOGLEVEL_CRITICAL = 0x00; //!< 0: these messages stop the program + const LOGLEVEL_ERROR = 0x01; //!< 1: everything that is really bad + const LOGLEVEL_WARNING = 0x02; //!< 2: everything that might be bad + const LOGLEVEL_DEBUG = 0x03; //!< 3: output that might help find a problem + const LOGLEVEL_INFO = 0x04; //!< 4: informational output + const LOGLEVEL_DEVEL = 0x05; //!< 5: development output + + /*@ + * TeamSpeak 3 token types. + */ + const TOKEN_SERVERGROUP = 0x00; //!< 0: server group token (id1={groupID} id2=0) + const TOKEN_CHANNELGROUP = 0x01; //!< 1: channel group token (id1={groupID} id2={channelID}) + + /*@ + * TeamSpeak 3 codec identifiers. + */ + const CODEC_SPEEX_NARROWBAND = 0x00; //!< 0: speex narrowband (mono, 16bit, 8kHz) + const CODEC_SPEEX_WIDEBAND = 0x01; //!< 1: speex wideband (mono, 16bit, 16kHz) + const CODEC_SPEEX_ULTRAWIDEBAND = 0x02; //!< 2: speex ultra-wideband (mono, 16bit, 32kHz) + const CODEC_CELT_MONO = 0x03; //!< 3: celt mono (mono, 16bit, 48kHz) + const CODEC_OPUS_VOICE = 0x04; //!< 3: opus voice (interactive) + const CODEC_OPUS_MUSIC = 0x05; //!< 3: opus music (interactive) + + /*@ + * TeamSpeak 3 codec encryption modes. + */ + const CODEC_CRYPT_INDIVIDUAL = 0x00; //!< 0: configure per channel + const CODEC_CRYPT_DISABLED = 0x01; //!< 1: globally disabled + const CODEC_CRYPT_ENABLED = 0x02; //!< 2: globally enabled + + /*@ + * TeamSpeak 3 kick reason types. + */ + const KICK_CHANNEL = 0x04; //!< 4: kick client from channel + const KICK_SERVER = 0x05; //!< 5: kick client from server + + /*@ + * TeamSpeak 3 text message target modes. + */ + const TEXTMSG_CLIENT = 0x01; //!< 1: target is a client + const TEXTMSG_CHANNEL = 0x02; //!< 2: target is a channel + const TEXTMSG_SERVER = 0x03; //!< 3: target is a virtual server + + /*@ + * TeamSpeak 3 plugin command target modes. + */ + const PLUGINCMD_CHANNEL = 0x01; //!< 1: send plugincmd to all clients in current channel + const PLUGINCMD_SERVER = 0x02; //!< 2: send plugincmd to all clients on server + const PLUGINCMD_CLIENT = 0x03; //!< 3: send plugincmd to all given client ids + const PLUGINCMD_CHANNEL_SUBSCRIBED = 0x04; //!< 4: send plugincmd to all subscribed clients in current channel + + /*@ + * TeamSpeak 3 host message modes. + */ + const HOSTMSG_NONE = 0x00; //!< 0: display no message + const HOSTMSG_LOG = 0x01; //!< 1: display message in chatlog + const HOSTMSG_MODAL = 0x02; //!< 2: display message in modal dialog + const HOSTMSG_MODALQUIT = 0x03; //!< 3: display message in modal dialog and close connection + + /*@ + * TeamSpeak 3 host banner modes. + */ + const HOSTBANNER_NO_ADJUST = 0x00; //!< 0: do not adjust + const HOSTBANNER_IGNORE_ASPECT = 0x01; //!< 1: adjust but ignore aspect ratio + const HOSTBANNER_KEEP_ASPECT = 0x02; //!< 2: adjust and keep aspect ratio + + /*@ + * TeamSpeak 3 client identification types. + */ + const CLIENT_TYPE_REGULAR = 0x00; //!< 0: regular client + const CLIENT_TYPE_SERVERQUERY = 0x01; //!< 1: query client + + /*@ + * TeamSpeak 3 permission group database types. + */ + const GROUP_DBTYPE_TEMPLATE = 0x00; //!< 0: template group (used for new virtual servers) + const GROUP_DBTYPE_REGULAR = 0x01; //!< 1: regular group (used for regular clients) + const GROUP_DBTYPE_SERVERQUERY = 0x02; //!< 2: global query group (used for ServerQuery clients) + + /*@ + * TeamSpeak 3 permission group name modes. + */ + const GROUP_NAMEMODE_HIDDEN = 0x00; //!< 0: display no name + const GROUP_NAMEMODE_BEFORE = 0x01; //!< 1: display name before client nickname + const GROUP_NAMEMODE_BEHIND = 0x02; //!< 2: display name after client nickname + + /*@ + * TeamSpeak 3 permission group identification types. + */ + const GROUP_IDENTIFIY_STRONGEST = 0x01; //!< 1: identify most powerful group + const GROUP_IDENTIFIY_WEAKEST = 0x02; //!< 2: identify weakest group + + /*@ + * TeamSpeak 3 permission types. + */ + const PERM_TYPE_SERVERGROUP = 0x00; //!< 0: server group permission + const PERM_TYPE_CLIENT = 0x01; //!< 1: client specific permission + const PERM_TYPE_CHANNEL = 0x02; //!< 2: channel specific permission + const PERM_TYPE_CHANNELGROUP = 0x03; //!< 3: channel group permission + const PERM_TYPE_CHANNELCLIENT = 0x04; //!< 4: channel-client specific permission + + /*@ + * TeamSpeak 3 permission categories. + */ + const PERM_CAT_GLOBAL = 0x10; //!< 00010000: global permissions + const PERM_CAT_GLOBAL_INFORMATION = 0x11; //!< 00010001: global permissions -> global information + const PERM_CAT_GLOBAL_SERVER_MGMT = 0x12; //!< 00010010: global permissions -> virtual server management + const PERM_CAT_GLOBAL_ADM_ACTIONS = 0x13; //!< 00010011: global permissions -> global administrative actions + const PERM_CAT_GLOBAL_SETTINGS = 0x14; //!< 00010100: global permissions -> global settings + const PERM_CAT_SERVER = 0x20; //!< 00100000: virtual server permissions + const PERM_CAT_SERVER_INFORMATION = 0x21; //!< 00100001: virtual server permissions -> virtual server information + const PERM_CAT_SERVER_ADM_ACTIONS = 0x22; //!< 00100010: virtual server permissions -> virtual server administrative actions + const PERM_CAT_SERVER_SETTINGS = 0x23; //!< 00100011: virtual server permissions -> virtual server settings + const PERM_CAT_CHANNEL = 0x30; //!< 00110000: channel permissions + const PERM_CAT_CHANNEL_INFORMATION = 0x31; //!< 00110001: channel permissions -> channel information + const PERM_CAT_CHANNEL_CREATE = 0x32; //!< 00110010: channel permissions -> create channels + const PERM_CAT_CHANNEL_MODIFY = 0x33; //!< 00110011: channel permissions -> edit channels + const PERM_CAT_CHANNEL_DELETE = 0x34; //!< 00110100: channel permissions -> delete channels + const PERM_CAT_CHANNEL_ACCESS = 0x35; //!< 00110101: channel permissions -> access channels + const PERM_CAT_GROUP = 0x40; //!< 01000000: group permissions + const PERM_CAT_GROUP_INFORMATION = 0x41; //!< 01000001: group permissions -> group information + const PERM_CAT_GROUP_CREATE = 0x42; //!< 01000010: group permissions -> create groups + const PERM_CAT_GROUP_MODIFY = 0x43; //!< 01000011: group permissions -> edit groups + const PERM_CAT_GROUP_DELETE = 0x44; //!< 01000100: group permissions -> delete groups + const PERM_CAT_CLIENT = 0x50; //!< 01010000: client permissions + const PERM_CAT_CLIENT_INFORMATION = 0x51; //!< 01010001: client permissions -> client information + const PERM_CAT_CLIENT_ADM_ACTIONS = 0x52; //!< 01010010: client permissions -> client administrative actions + const PERM_CAT_CLIENT_BASICS = 0x53; //!< 01010011: client permissions -> client basic communication + const PERM_CAT_CLIENT_MODIFY = 0x54; //!< 01010100: client permissions -> edit clients + const PERM_CAT_FILETRANSFER = 0x60; //!< 01100000: file transfer permissions + const PERM_CAT_NEEDED_MODIFY_POWER = 0xFF; //!< 11111111: needed permission modify power (grant) permissions + + /*@ + * TeamSpeak 3 file types. + */ + const FILE_TYPE_DIRECTORY = 0x00; //!< 0: file is directory + const FILE_TYPE_REGULAR = 0x01; //!< 1: file is regular + + /*@ + * TeamSpeak 3 server snapshot types. + */ + const SNAPSHOT_STRING = 0x00; //!< 0: default string + const SNAPSHOT_BASE64 = 0x01; //!< 1: base64 string + const SNAPSHOT_HEXDEC = 0x02; //!< 2: hexadecimal string + + /*@ + * TeamSpeak 3 channel spacer types. + */ + const SPACER_SOLIDLINE = 0x00; //!< 0: solid line + const SPACER_DASHLINE = 0x01; //!< 1: dash line + const SPACER_DOTLINE = 0x02; //!< 2: dot line + const SPACER_DASHDOTLINE = 0x03; //!< 3: dash dot line + const SPACER_DASHDOTDOTLINE = 0x04; //!< 4: dash dot dot line + const SPACER_CUSTOM = 0x05; //!< 5: custom format + + /*@ + * TeamSpeak 3 channel spacer alignments. + */ + const SPACER_ALIGN_LEFT = 0x00; //!< 0: alignment left + const SPACER_ALIGN_RIGHT = 0x01; //!< 1: alignment right + const SPACER_ALIGN_CENTER = 0x02; //!< 2: alignment center + const SPACER_ALIGN_REPEAT = 0x03; //!< 3: repeat until the whole line is filled + + /*@ + * TeamSpeak 3 reason identifiers. + */ + const REASON_NONE = 0x00; //!< 0: no reason + const REASON_MOVE = 0x01; //!< 1: channel switched or moved + const REASON_SUBSCRIPTION = 0x02; //!< 2: subscription added or removed + const REASON_TIMEOUT = 0x03; //!< 3: client connection timed out + const REASON_CHANNEL_KICK = 0x04; //!< 4: client kicked from channel + const REASON_SERVER_KICK = 0x05; //!< 5: client kicked from server + const REASON_SERVER_BAN = 0x06; //!< 6: client banned from server + const REASON_SERVER_STOP = 0x07; //!< 7: server stopped + const REASON_DISCONNECT = 0x08; //!< 8: client disconnected + const REASON_CHANNEL_UPDATE = 0x09; //!< 9: channel information updated + const REASON_CHANNEL_EDIT = 0x0A; //!< 10: channel information edited + const REASON_DISCONNECT_SHUTDOWN = 0x0B; //!< 11: client disconnected on server shutdown + + /** + * Stores an array containing various chars which need to be escaped while communicating + * with a TeamSpeak 3 Server. + * + * @var array + */ + protected static $escape_patterns = array( + "\\" => "\\\\", // backslash + "/" => "\\/", // slash + " " => "\\s", // whitespace + "|" => "\\p", // pipe + ";" => "\\;", // semicolon + "\a" => "\\a", // bell + "\b" => "\\b", // backspace + "\f" => "\\f", // formfeed + "\n" => "\\n", // newline + "\r" => "\\r", // carriage return + "\t" => "\\t", // horizontal tab + "\v" => "\\v" // vertical tab + ); + + /** + * Factory for TeamSpeak3_Adapter_Abstract classes. $uri must be formatted as + * "://:@:/#". All parameters + * except adapter, host and port are optional. + * + * === Supported Options === + * - timeout + * - blocking + * - nickname + * - no_query_clients + * - use_offline_as_virtual + * - clients_before_channels + * - server_id|server_uid|server_port|server_name|server_tsdns + * - channel_id|channel_name + * - client_id|client_uid|client_name + * + * === Supported Flags (only one per $uri) === + * - no_query_clients + * - use_offline_as_virtual + * - clients_before_channels + * + * === URI Examples === + * - serverquery://127.0.0.1:10011/ + * - serverquery://127.0.0.1:10011/?server_port=9987&channel_id=1 + * - serverquery://127.0.0.1:10011/?server_port=9987&channel_id=1#no_query_clients + * - serverquery://127.0.0.1:10011/?server_port=9987&client_name=ScP + * - filetransfer://127.0.0.1:30011/ + * - blacklist + * - update + * + * @param string $uri + * @return TeamSpeak3_Adapter_Abstract + * @return TeamSpeak3_Node_Abstract + * @return TeamSpeak3_Node_Host + * @return TeamSpeak3_Node_Server + */ + public static function factory($uri) + { + self::init(); + + $uri = new TeamSpeak3_Helper_Uri($uri); + + $adapter = self::getAdapterName($uri->getScheme()); + $options = array("host" => $uri->getHost(), "port" => $uri->getPort(), "timeout" => (int) $uri->getQueryVar("timeout", 10), "blocking" => (int) $uri->getQueryVar("blocking", 1)); + + self::loadClass($adapter); + + $object = new $adapter($options); + + if($object instanceof TeamSpeak3_Adapter_ServerQuery) + { + $node = $object->getHost(); + + if($uri->hasUser() && $uri->hasPass()) + { + $node->login($uri->getUser(), $uri->getPass()); + } + + if($uri->hasQueryVar("nickname")) + { + $node->setPredefinedQueryName($uri->getQueryVar("nickname")); + } + + if($uri->getFragment() == "use_offline_as_virtual") + { + $node->setUseOfflineAsVirtual(TRUE); + } + elseif($uri->hasQueryVar("use_offline_as_virtual")) + { + $node->setUseOfflineAsVirtual($uri->getQueryVar("use_offline_as_virtual") ? TRUE : FALSE); + } + + if($uri->getFragment() == "clients_before_channels") + { + $node->setLoadClientlistFirst(TRUE); + } + elseif($uri->hasQueryVar("clients_before_channels")) + { + $node->setLoadClientlistFirst($uri->getQueryVar("clients_before_channels") ? TRUE : FALSE); + } + + if($uri->getFragment() == "no_query_clients") + { + $node->setExcludeQueryClients(TRUE); + } + elseif($uri->hasQueryVar("no_query_clients")) + { + $node->setExcludeQueryClients($uri->getQueryVar("no_query_clients") ? TRUE : FALSE); + } + + if($uri->hasQueryVar("server_id")) + { + $node = $node->serverGetById($uri->getQueryVar("server_id")); + } + elseif($uri->hasQueryVar("server_uid")) + { + $node = $node->serverGetByUid($uri->getQueryVar("server_uid")); + } + elseif($uri->hasQueryVar("server_port")) + { + $node = $node->serverGetByPort($uri->getQueryVar("server_port")); + } + elseif($uri->hasQueryVar("server_name")) + { + $node = $node->serverGetByName($uri->getQueryVar("server_name")); + } + elseif($uri->hasQueryVar("server_tsdns")) + { + $node = $node->serverGetByTSDNS($uri->getQueryVar("server_tsdns")); + } + + if($node instanceof TeamSpeak3_Node_Server) + { + if($uri->hasQueryVar("channel_id")) + { + $node = $node->channelGetById($uri->getQueryVar("channel_id")); + } + elseif($uri->hasQueryVar("channel_name")) + { + $node = $node->channelGetByName($uri->getQueryVar("channel_name")); + } + + if($uri->hasQueryVar("client_id")) + { + $node = $node->clientGetById($uri->getQueryVar("client_id")); + } + if($uri->hasQueryVar("client_uid")) + { + $node = $node->clientGetByUid($uri->getQueryVar("client_uid")); + } + elseif($uri->hasQueryVar("client_name")) + { + $node = $node->clientGetByName($uri->getQueryVar("client_name")); + } + } + + return $node; + } + + return $object; + } + + /** + * Loads a class from a PHP file. The filename must be formatted as "$class.php". + * + * include() is not prefixed with the @ operator because if the file is loaded and + * contains a parse error, execution will halt silently and this is difficult to debug. + * + * @param string $class + * @throws LogicException + * @return boolean + */ + protected static function loadClass($class) + { + if(class_exists($class, FALSE) || interface_exists($class, FALSE)) + { + return; + } + + if(preg_match("/[^a-z0-9\\/\\\\_.-]/i", $class)) + { + throw new LogicException("illegal characters in classname '" . $class . "'"); + } + + $file = self::getFilePath($class) . ".php"; + + if(!file_exists($file) || !is_readable($file)) + { + throw new LogicException("file '" . $file . "' does not exist or is not readable"); + } + + if(class_exists($class, FALSE) || interface_exists($class, FALSE)) + { + throw new LogicException("class '" . $class . "' does not exist"); + } + + return include_once($file); + } + + /** + * Generates a possible file path for $name. + * + * @param string $name + * @return string + */ + protected static function getFilePath($name) + { + $path = str_replace("_", DIRECTORY_SEPARATOR, $name); + $path = str_replace(__CLASS__, dirname(__FILE__), $path); + + return $path; + } + + /** + * Returns the name of an adapter class by $name. + * + * @param string $name + * @param string $namespace + * @throws TeamSpeak3_Adapter_Exception + * @return string + */ + protected static function getAdapterName($name, $namespace = "TeamSpeak3_Adapter_") + { + $path = self::getFilePath($namespace); + $scan = scandir($path); + + foreach($scan as $node) + { + $file = TeamSpeak3_Helper_String::factory($node)->toLower(); + + if($file->startsWith($name) && $file->endsWith(".php")) + { + return $namespace . str_replace(".php", "", $node); + } + } + + throw new TeamSpeak3_Adapter_Exception("adapter '" . $name . "' does not exist"); + } + + /** + * spl_autoload() suitable implementation for supporting class autoloading. + * + * @param string $class + * @return boolean + */ + public static function autoload($class) + { + if(substr($class, 0, strlen(__CLASS__)) != __CLASS__) return; + + try + { + self::loadClass($class); + + return TRUE; + } + catch(Exception $e) + { + return FALSE; + } + } + + /** + * Checks for required PHP features, enables autoloading and starts a default profiler. + * + * @throws LogicException + * @return void + */ + public static function init() + { + if(version_compare(phpversion(), "5.2.1") == -1) + { + throw new LogicException("this particular software cannot be used with the installed version of PHP"); + } + + if(!function_exists("stream_socket_client")) + { + throw new LogicException("network functions are not available in this PHP installation"); + } + + if(!function_exists("spl_autoload_register")) + { + throw new LogicException("autoload functions are not available in this PHP installation"); + } + + if(!class_exists("TeamSpeak3_Helper_Profiler")) + { + spl_autoload_register(array(__CLASS__, "autoload")); + } + + TeamSpeak3_Helper_Profiler::start(); + } + + /** + * Returns an assoc array containing all escape patterns available on a TeamSpeak 3 + * Server. + * + * @return array + */ + public static function getEscapePatterns() + { + return self::$escape_patterns; + } + + /** + * Debug helper function. This is a wrapper for var_dump() that adds the pre-format tags, + * cleans up newlines and indents, and runs htmlentities() before output. + * + * @param mixed $var + * @param bool $echo + * @return string + */ + public static function dump($var, $echo = TRUE) + { + ob_start(); + var_dump($var); + + $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", ob_get_clean()); + + if(PHP_SAPI == "cli") + { + $output = PHP_EOL . PHP_EOL . $output . PHP_EOL; + } + else + { + $output = "
" . htmlspecialchars($output, ENT_QUOTES, "utf-8") . "
"; + } + + if($echo) echo($output); + + return $output; + } +} + +/*! + * \mainpage API Documentation + * + * \section welcome_sec Introduction + * + * \subsection welcome1 What is the TS3 PHP Framework? + * Initially released in January 2010, the TS3 PHP Framework is a powerful, open source, object-oriented framework + * implemented in PHP 5 and licensed under the GNU General Public License. It's based on simplicity and a rigorously + * tested agile codebase. Extend the functionality of your servers with scripts or create powerful web applications + * to manage all features of your TeamSpeak 3 Server instances. + * + * Tested. Thoroughly. Enterprise-ready and built with agile methods, the TS3 PHP Framework has been unit-tested from + * the start to ensure that all code remains stable and easy for you to extend, re-test with your extensions, and + * further maintain. + * + * \subsection welcome2 Why should I use the TS3 PHP Framework rather than other PHP libraries? + * The TS3 PHP Framework is a is a modern use-at-will framework that provides individual components to communicate + * with the TeamSpeak 3 Server. + * + * There are lots of arguments for the TS3 PHP Framework in comparison with other PHP based libraries. It is the most + * dynamic and feature-rich piece of software in its class. In addition, it's always up-to-date and 100% compatible to + * almost any TeamSpeak 3 Server version available. + * + * \section sysreqs_sec Requirements + * The TS3 PHP Framework currently supports PHP 5.2.1 or later, but we strongly recommend the most current release of + * PHP for critical security and performance enhancements. If you want to create a web application using the TS3 PHP + * Framework, you need a PHP 5 interpreter with a web server configured to handle PHP scripts correctly. + * + * Note that the majority of TS3 PHP Framework development and deployment is done on nginx, so there is more community + * experience and testing performed on nginx than on other web servers. + * + * \section feature_sec Features + * Features of the TS3 PHP Framework include: + * + * - Fully object-oriented PHP 5 and E_STRICT compliant components + * - Access to all TeamSpeak 3 Server features via ServerQuery + * - Integrated full featured and customizable TSViewer interfaces + * - Full support for file transfers to up- and /or download custom icons and other stuff + * - Powerful error handling capablities using exceptions and customizable error messages + * - Query mechanisms for several official services such as the blacklist and auto-update servers + * - Dynamic signal slots for event based scripting + * - ... + * + * \section example_sec Usage Examples + * + * \subsection example1 1. Kick a single Client from a Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // kick the client with ID 123 from the server + * $ts3_VirtualServer->clientKick(123, TeamSpeak3::KICK_SERVER, "evil kick XD"); + * + * // spawn an object for the client by unique identifier and do the kick + * $ts3_VirtualServer->clientGetByUid("FPMPSC6MXqXq751dX7BKV0JniSo=")->kick(TeamSpeak3::KICK_SERVER, "evil kick XD"); + * + * // spawn an object for the client by current nickname and do the kick + * $ts3_VirtualServer->clientGetByName("ScP")->kick(TeamSpeak3::KICK_SERVER, "evil kick XD"); + * @endcode + * + * \subsection example2 2. Kick all Clients from a Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // query clientlist from virtual server + * $arr_ClientList = $ts3_VirtualServer->clientList(); + * + * // kick all clients online with a single command + * $ts3_VirtualServer->clientKick($arr_ClientList, TeamSpeak3::KICK_SERVER, "evil kick XD"); + * @endcode + * + * \subsection example3 3. Print the Nicknames of connected Android Clients + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // query clientlist from virtual server and filter by platform + * $arr_ClientList = $ts3_VirtualServer->clientList(array("client_platform" => "Android")); + * + * // walk through list of clients + * foreach($arr_ClientList as $ts3_Client) + * { + * echo $ts3_Client . " is using " . $ts3_Client["client_platform"] . "
\n"; + * } + * @endcode + * + * \subsection example4 4. Modify the Settings of each Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the server instance + * $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/"); + * + * // walk through list of virtual servers + * foreach($ts3_ServerInstance as $ts3_VirtualServer) + * { + * // modify the virtual servers hostbanner URL only using the ArrayAccess interface + * $ts3_VirtualServer["virtualserver_hostbanner_gfx_url"] = "http://www.example.com/banners/banner01_468x60.jpg"; + * + * // modify the virtual servers hostbanner URL only using property overloading + * $ts3_VirtualServer->virtualserver_hostbanner_gfx_url = "http://www.example.com/banners/banner01_468x60.jpg"; + * + * // modify multiple virtual server properties at once + * $ts3_VirtualServer->modify(array( + * "virtualserver_hostbutton_tooltip" => "My Company", + * "virtualserver_hostbutton_url" => "http://www.example.com", + * "virtualserver_hostbutton_gfx_url" => "http://www.example.com/buttons/button01_24x24.jpg", + * )); + * } + * @endcode + * + * \subsection example5 5. Create a Privilege Key for a Server Group + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // spawn an object for the group using a specified name + * $arr_ServerGroup = $ts3_VirtualServer->serverGroupGetByName("Admins"); + * + * // create the privilege key + * $ts3_PrivilegeKey = $arr_ServerGroup->privilegeKeyCreate(); + * @endcode + * + * \subsection example6 6. Modify the Permissions of Admins on each Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the server instance + * $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/"); + * + * // walk through list of virtual servers + * foreach($ts3_ServerInstance as $ts3_VirtualServer) + * { + * // identify the most powerful group on the virtual server + * $ts3_ServerGroup = $ts3_VirtualServer->serverGroupIdentify(); + * + * // assign a new permission + * $ts3_ServerGroup->permAssign("b_virtualserver_modify_hostbanner", TRUE); + * + * // revoke an existing permission + * $ts3_ServerGroup->permRemove("b_virtualserver_modify_maxclients"); + * } + * @endcode + * + * \subsection example7 7. Create a new Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the server instance + * $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/"); + * + * // create a virtual server and get its ID + * $new_sid = $ts3_ServerInstance->serverCreate(array( + * "virtualserver_name" => "My TeamSpeak 3 Server", + * "virtualserver_maxclients" => 64, + * "virtualserver_hostbutton_tooltip" => "My Company", + * "virtualserver_hostbutton_url" => "http://www.example.com", + * "virtualserver_hostbutton_gfx_url" => "http://www.example.com/buttons/button01_24x24.jpg", + * )); + * @endcode + * + * \subsection example8 8. Create a hierarchical Channel Stucture + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // create a top-level channel and get its ID + * $top_cid = $ts3_VirtualServer->channelCreate(array( + * "channel_name" => "My Channel", + * "channel_topic" => "This is a top-level channel", + * "channel_codec" => TeamSpeak3::CODEC_SPEEX_WIDEBAND, + * "channel_flag_permanent" => TRUE, + * )); + * + * // create a sub-level channel and get its ID + * $sub_cid = $ts3_VirtualServer->channelCreate(array( + * "channel_name" => "My Sub-Channel", + * "channel_topic" => "This is a sub-level channel", + * "channel_codec" => TeamSpeak3::CODEC_SPEEX_NARROWBAND, + * "channel_flag_permanent" => TRUE, + * "cpid" => $top_cid, + * )); + * @endcode + * + * \subsection example9 9. Send a Text Message to outdated Clients + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // connect to default update server + * $ts3_UpdateServer = TeamSpeak3::factory("update"); + * + * // walk through list of clients on virtual server + * foreach($ts3_VirtualServer->clientList() as $ts3_Client) + * { + * // skip query clients + * if($ts3_Client["client_type"]) continue; + * + * // send test message if client build is outdated + * if($ts3_Client->getRev() < $ts3_UpdateServer->getClientRev()) + * { + * $ts3_Client->message("[COLOR=red]your client is [B]outdated[/B]... update to [U]" . $ts3_UpdateServer->getClientVersion() . "[/U] now![/COLOR]"); + * } + * } + * @endcode + * + * \subsection example10 10. Check if the Server Instance is Outdated or Blacklisted + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the server instance + * $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/"); + * + * // connect to default update server + * $ts3_UpdateServer = TeamSpeak3::factory("update"); + * + * // send global text message if the server is outdated + * if($ts3_ServerInstance->version("build") < $ts3_UpdateServer->getServerRev()) + * { + * $ts3_ServerInstance->message("[COLOR=red]your server is [B]outdated[/B]... update to [U]" . $ts3_UpdateServer->getServerVersion() . "[/U] now![/COLOR]"); + * } + * + * // connect to default blacklist server + * $ts3_BlacklistServer = TeamSpeak3::factory("blacklist"); + * + * // send global text message if the server is blacklisted + * if($ts3_BlacklistServer->isBlacklisted($ts3_ServerInstance)) + * { + * $ts3_ServerInstance->message("[COLOR=red]your server is [B]blacklisted[/B]... disconnect now![/COLOR]"); + * } + * @endcode + * + * \subsection example11 11. Create a simple TSViewer for your Website + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // build and display HTML treeview using custom image paths (remote icons will be embedded using data URI sheme) + * echo $ts3_VirtualServer->getViewer(new TeamSpeak3_Viewer_Html("images/viewericons/", "images/countryflags/", "data:image")); + * @endcode + * + * \subsection example12 12. Update all outdated Audio Codecs to their Opus equivalent + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // walk through list of chanels + * foreach($ts3_VirtualServer->channelList() as $ts3_Channel) + * { + * if($ts3_Channel["channel_codec"] == TeamSpeak3::CODEC_CELT_MONO) + * { + * $ts3_Channel["channel_codec"] = TeamSpeak3::CODEC_OPUS_MUSIC; + * } + * elseif($ts3_Channel["channel_codec"] != TeamSpeak3::CODEC_OPUS_MUSIC) + * { + * $ts3_Channel["channel_codec"] = TeamSpeak3::CODEC_OPUS_VOICE; + * } + * } + * @endcode + * + * \subsection example13 13. Display the Avatar of a connected User + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // spawn an object for the client using a specified nickname + * $ts3_Client = $ts3_VirtualServer->clientGetByName("John Doe"); + * + * // download the clients avatar file + * $avatar = $ts3_Client->avatarDownload(); + * + * // send header and display image + * header("Content-Type: " . TeamSpeak3_Helper_Convert::imageMimeType($avatar)); + * echo $avatar; + * @endcode + * + * \subsection example14 14. Create a Simple Bot waiting for Events + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server in non-blocking mode, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987&blocking=0"); + * + * // get notified on incoming private messages + * $ts3_VirtualServer->notifyRegister("textprivate"); + * + * // register a callback for notifyTextmessage events + * TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyTextmessage", "onTextmessage"); + * + * // wait for events + * while(1) $ts3_VirtualServer->getAdapter()->wait(); + * + * // define a callback function + * function onTextmessage(TeamSpeak3_Adapter_ServerQuery_Event $event, TeamSpeak3_Node_Host $host) + * { + * echo "Client " . $event["invokername"] . " sent textmessage: " . $event["msg"]; + * } + * @endcode + * + * \subsection example15 15. Handle Errors using Exceptions and Custom Error Messages + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // register custom error message (supported placeholders are: %file, %line, %code and %mesg) + * TeamSpeak3_Exception::registerCustomMessage(0x300, "The specified channel does not exist; server said: %mesg"); + * + * try + * { + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // spawn an object for the channel using a specified name + * $ts3_Channel = $ts3_VirtualServer->channelGetByName("I do not exist"); + * } + * catch(TeamSpeak3_Exception $e) + * { + * // print the error message returned by the server + * echo "Error " . $e->getCode() . ": " . $e->getMessage(); + * } + * @endcode + * + * \subsection example16 16. Save Connection State in Persistent Session Variable + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // start a PHP session + * session_start(); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // save connection state (including login and selected virtual server) + * $_SESSION["_TS3"] = serialize($ts3_VirtualServer); + * @endcode + * + * \subsection example17 17. Restore Connection State from Persistent Session Variable + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // start a PHP session + * session_start(); + * + * // restore connection state + * $ts3_VirtualServer = unserialize($_SESSION["_TS3"]); + * + * // send a text message to the server + * $ts3_VirtualServer->message("Hello World!"); + * @endcode + * + * Speed up new development and reduce maintenance costs by using the TS3 PHP Framework! + */ diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Transport/Abstract.php b/lib/ts3phpframework/libraries/TeamSpeak3/Transport/Abstract.php new file mode 100644 index 0000000..5350aa5 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Transport/Abstract.php @@ -0,0 +1,270 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Transport_Abstract + * @brief Abstract class for connecting to a TeamSpeak 3 Server through different ways of transport. + */ +abstract class TeamSpeak3_Transport_Abstract +{ + /** + * Stores user-provided configuration settings. + * + * @var array + */ + protected $config = null; + + /** + * Stores the stream resource of the connection. + * + * @var resource + */ + protected $stream = null; + + /** + * Stores the TeamSpeak3_Adapter_Abstract object using this transport. + * + * @var TeamSpeak3_Adapter_Abstract + */ + protected $adapter = null; + + /** + * The TeamSpeak3_Transport_Abstract constructor. + * + * @param array $config + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Transport_Abstract + */ + public function __construct(array $config) + { + if(!array_key_exists("host", $config)) + { + throw new TeamSpeak3_Transport_Exception("config must have a key for 'host' which specifies the server host name"); + } + + if(!array_key_exists("port", $config)) + { + throw new TeamSpeak3_Transport_Exception("config must have a key for 'port' which specifies the server port number"); + } + + if(!array_key_exists("timeout", $config)) + { + $config["timeout"] = 10; + } + + if(!array_key_exists("blocking", $config)) + { + $config["blocking"] = 1; + } + + $this->config = $config; + } + + /** + * Commit pending data. + * + * @return array + */ + public function __sleep() + { + return array("config"); + } + + /** + * Reconnects to the remote server. + * + * @return void + */ + public function __wakeup() + { + $this->connect(); + } + + /** + * The TeamSpeak3_Transport_Abstract destructor. + * + * @return void + */ + public function __destruct() + { + if($this->adapter instanceof TeamSpeak3_Adapter_Abstract) + { + $this->adapter->__destruct(); + } + + $this->disconnect(); + } + + /** + * Connects to a remote server. + * + * @throws TeamSpeak3_Transport_Exception + * @return void + */ + abstract public function connect(); + + /** + * Disconnects from a remote server. + * + * @return void + */ + abstract public function disconnect(); + + /** + * Reads data from the stream. + * + * @param integer $length + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Helper_String + */ + abstract public function read($length = 4096); + + /** + * Writes data to the stream. + * + * @param string $data + * @return void + */ + abstract public function send($data); + + /** + * Returns the underlying stream resource. + * + * @return resource + */ + public function getStream() + { + return $this->stream; + } + + /** + * Returns the configuration variables in this adapter. + * + * @param string $key + * @param mixed $default + * @return array + */ + public function getConfig($key = null, $default = null) + { + if($key !== null) + { + return array_key_exists($key, $this->config) ? $this->config[$key] : $default; + } + + return $this->config; + } + + /** + * Sets the TeamSpeak3_Adapter_Abstract object using this transport. + * + * @param TeamSpeak3_Adapter_Abstract $adapter + * @return void + */ + public function setAdapter(TeamSpeak3_Adapter_Abstract $adapter) + { + $this->adapter = $adapter; + } + + /** + * Returns the TeamSpeak3_Adapter_Abstract object using this transport. + * + * @return TeamSpeak3_Adapter_Abstract + */ + public function getAdapter() + { + return $this->adapter; + } + + /** + * Returns the adapter type. + * + * @return string + */ + public function getAdapterType() + { + if($this->adapter instanceof TeamSpeak3_Adapter_Abstract) + { + $string = TeamSpeak3_Helper_String::factory(get_class($this->adapter)); + + return $string->substr($string->findLast("_"))->replace(array("_", " "), "")->toString(); + } + + return "Unknown"; + } + + /** + * Returns header/meta data from stream pointer. + * + * @throws TeamSpeak3_Transport_Exception + * @return array + */ + public function getMetaData() + { + if($this->stream === null) + { + throw new TeamSpeak3_Transport_Exception("unable to retrieve header/meta data from stream pointer"); + } + + return stream_get_meta_data($this->stream); + } + + /** + * Returns TRUE if the transport is connected. + * + * @return boolean + */ + public function isConnected() + { + return (is_resource($this->stream)) ? TRUE : FALSE; + } + + /** + * Blocks a stream until data is available for reading if the stream is connected + * in non-blocking mode. + * + * @param integer $time + * @return void + */ + protected function waitForReadyRead($time = 0) + { + if(!$this->isConnected() || $this->config["blocking"]) return; + + do + { + $read = array($this->stream); + $null = null; + + if($time) + { + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "WaitTimeout", $time, $this->getAdapter()); + } + + $time = $time+$this->config["timeout"]; + } + while(@stream_select($read, $null, $null, $this->config["timeout"]) == 0); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Transport/Exception.php b/lib/ts3phpframework/libraries/TeamSpeak3/Transport/Exception.php new file mode 100644 index 0000000..c7e68eb --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Transport/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Transport_Exception + * @brief Enhanced exception class for TeamSpeak3_Transport_Abstract objects. + */ +class TeamSpeak3_Transport_Exception extends TeamSpeak3_Exception {} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Transport/TCP.php b/lib/ts3phpframework/libraries/TeamSpeak3/Transport/TCP.php new file mode 100644 index 0000000..4ee349b --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Transport/TCP.php @@ -0,0 +1,179 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Transport_TCP + * @brief Class for connecting to a remote server through TCP. + */ +class TeamSpeak3_Transport_TCP extends TeamSpeak3_Transport_Abstract +{ + /** + * Connects to a remote server. + * + * @throws TeamSpeak3_Transport_Exception + * @return void + */ + public function connect() + { + if($this->stream !== null) return; + + $host = strval($this->config["host"]); + $port = strval($this->config["port"]); + + $address = "tcp://" . (strstr($host, ":") !== FALSE ? "[" . $host . "]" : $host) . ":" . $port; + $timeout = (int) $this->config["timeout"]; + + $this->stream = @stream_socket_client($address, $errno, $errstr, $timeout); + + if($this->stream === FALSE) + { + throw new TeamSpeak3_Transport_Exception(TeamSpeak3_Helper_String::factory($errstr)->toUtf8()->toString(), $errno); + } + + @stream_set_timeout($this->stream, $timeout); + @stream_set_blocking($this->stream, $this->config["blocking"] ? 1 : 0); + } + + /** + * Disconnects from a remote server. + * + * @return void + */ + public function disconnect() + { + if($this->stream === null) return; + + $this->stream = null; + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "Disconnected"); + } + + /** + * Reads data from the stream. + * + * @param integer $length + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Helper_String + */ + public function read($length = 4096) + { + $this->connect(); + $this->waitForReadyRead(); + + $data = @stream_get_contents($this->stream, $length); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataRead", $data); + + if($data === FALSE) + { + throw new TeamSpeak3_Transport_Exception("connection to server '" . $this->config["host"] . ":" . $this->config["port"] . "' lost"); + } + + return new TeamSpeak3_Helper_String($data); + } + + /** + * Reads a single line of data from the stream. + * + * @param string $token + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Helper_String + */ + public function readLine($token = "\n") + { + $this->connect(); + + $line = TeamSpeak3_Helper_String::factory(""); + + while(!$line->endsWith($token)) + { + $this->waitForReadyRead(); + + $data = @fgets($this->stream, 4096); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataRead", $data); + + if($data === FALSE) + { + if($line->count()) + { + $line->append($token); + } + else + { + throw new TeamSpeak3_Transport_Exception("connection to server '" . $this->config["host"] . ":" . $this->config["port"] . "' lost"); + } + } + else + { + $line->append($data); + } + } + + return $line->trim(); + } + + /** + * Writes data to the stream. + * + * @param string $data + * @return void + */ + public function send($data) + { + $this->connect(); + + @stream_socket_sendto($this->stream, $data); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataSend", $data); + } + + /** + * Writes a line of data to the stream. + * + * @param string $data + * @param string $separator + * @return void + */ + public function sendLine($data, $separator = "\n") + { + $size = strlen($data); + $pack = 4096; + + for($seek = 0 ;$seek < $size;) + { + $rest = $size-$seek; + $pack = $rest < $pack ? $rest : $pack; + $buff = substr($data, $seek, $pack); + $seek = $seek+$pack; + + if($seek >= $size) $buff .= $separator; + + $this->send($buff); + } + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Transport/UDP.php b/lib/ts3phpframework/libraries/TeamSpeak3/Transport/UDP.php new file mode 100644 index 0000000..e0df880 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Transport/UDP.php @@ -0,0 +1,113 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Transport_UDP + * @brief Class for connecting to a remote server through UDP. + */ +class TeamSpeak3_Transport_UDP extends TeamSpeak3_Transport_Abstract +{ + /** + * Connects to a remote server. + * + * @throws TeamSpeak3_Transport_Exception + * @return void + */ + public function connect() + { + if($this->stream !== null) return; + + $host = strval($this->config["host"]); + $port = strval($this->config["port"]); + + $address = "udp://" . (strstr($host, ":") !== FALSE ? "[" . $host . "]" : $host) . ":" . $port; + $timeout = (int) $this->config["timeout"]; + + $this->stream = @stream_socket_client($address, $errno, $errstr, $timeout); + + if($this->stream === FALSE) + { + throw new TeamSpeak3_Transport_Exception(TeamSpeak3_Helper_String::factory($errstr)->toUtf8()->toString(), $errno); + } + + @stream_set_timeout($this->stream, $timeout); + @stream_set_blocking($this->stream, $this->config["blocking"] ? 1 : 0); + } + + /** + * Disconnects from a remote server. + * + * @return void + */ + public function disconnect() + { + if($this->stream === null) return; + + $this->stream = null; + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "Disconnected"); + } + + /** + * Reads data from the stream. + * + * @param integer $length + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Helper_String + */ + public function read($length = 4096) + { + $this->connect(); + $this->waitForReadyRead(); + + $data = @fread($this->stream, $length); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataRead", $data); + + if($data === FALSE) + { + throw new TeamSpeak3_Transport_Exception("connection to server '" . $this->config["host"] . ":" . $this->config["port"] . "' lost"); + } + + return new TeamSpeak3_Helper_String($data); + } + + /** + * Writes data to the stream. + * + * @param string $data + * @return void + */ + public function send($data) + { + $this->connect(); + + @stream_socket_sendto($this->stream, $data); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataSend", $data); + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Viewer/Html.php b/lib/ts3phpframework/libraries/TeamSpeak3/Viewer/Html.php new file mode 100644 index 0000000..155fd54 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Viewer/Html.php @@ -0,0 +1,670 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Viewer_Html + * @brief Renders nodes used in HTML-based TeamSpeak 3 viewers. + */ +class TeamSpeak3_Viewer_Html implements TeamSpeak3_Viewer_Interface +{ + /** + * A pre-defined pattern used to display a node in a TeamSpeak 3 viewer. + * + * @var string + */ + protected $pattern = "
%5%8 %9%11%12
\n"; + + /** + * The TeamSpeak3_Node_Abstract object which is currently processed. + * + * @var TeamSpeak3_Node_Abstract + */ + protected $currObj = null; + + /** + * An array filled with siblingsfor the TeamSpeak3_Node_Abstract object which is currently + * processed. + * + * @var array + */ + protected $currSib = null; + + /** + * An internal counter indicating the number of fetched TeamSpeak3_Node_Abstract objects. + * + * @var integer + */ + protected $currNum = 0; + + /** + * The relative URI path where the images used by the viewer can be found. + * + * @var string + */ + protected $iconpath = null; + + /** + * The relative URI path where the country flag icons used by the viewer can be found. + * + * @var string + */ + protected $flagpath = null; + + /** + * The relative path of the file transter client script on the server. + * + * @var string + */ + protected $ftclient = null; + + /** + * Stores an array of local icon IDs. + * + * @var array + */ + protected $cachedIcons = array(100, 200, 300, 400, 500, 600); + + /** + * Stores an array of remote icon IDs. + * + * @var array + */ + protected $remoteIcons = array(); + + /** + * The TeamSpeak3_Viewer_Html constructor. + * + * @param string $iconpath + * @param string $flagpath + * @param string $ftclient + * @param string $pattern + * @return void + */ + public function __construct($iconpath = "images/viewer/", $flagpath = null, $ftclient = null, $pattern = null) + { + $this->iconpath = $iconpath; + $this->flagpath = $flagpath; + $this->ftclient = $ftclient; + + if($pattern) + { + $this->pattern = $pattern; + } + } + + /** + * Returns the code needed to display a node in a TeamSpeak 3 viewer. + * + * @param TeamSpeak3_Node_Abstract $node + * @param array $siblings + * @return string + */ + public function fetchObject(TeamSpeak3_Node_Abstract $node, array $siblings = array()) + { + $this->currObj = $node; + $this->currSib = $siblings; + + $args = array( + $this->getContainerIdent(), + $this->getContainerClass(), + $this->getContainerSummary(), + $this->getRowClass(), + $this->getPrefixClass(), + $this->getPrefix(), + $this->getCorpusClass(), + $this->getCorpusTitle(), + $this->getCorpusIcon(), + $this->getCorpusName(), + $this->getSuffixClass(), + $this->getSuffixIcon(), + $this->getSuffixFlag(), + ); + + return TeamSpeak3_Helper_String::factory($this->pattern)->arg($args); + } + + /** + * Returns a unique identifier for the current node which can be used as a HTML id + * property. + * + * @return string + */ + protected function getContainerIdent() + { + return $this->currObj->getUniqueId(); + } + + /** + * Returns a dynamic string for the current container element which can be used as + * a HTML class property. + * + * @return string + */ + protected function getContainerClass() + { + return "ts3_viewer " . $this->currObj->getClass(null); + } + + /** + * Returns the ID of the current node which will be used as a summary element for + * the container element. + * + * @return integer + */ + protected function getContainerSummary() + { + return $this->currObj->getId(); + } + + /** + * Returns a dynamic string for the current row element which can be used as a HTML + * class property. + * + * @return string + */ + protected function getRowClass() + { + return ++$this->currNum%2 ? "row1" : "row2"; + } + + /** + * Returns a string for the current prefix element which can be used as a HTML class + * property. + * + * @return string + */ + protected function getPrefixClass() + { + return "prefix " . $this->currObj->getClass(null); + } + + /** + * Returns the HTML img tags to display the prefix of the current node. + * + * @return string + */ + protected function getPrefix() + { + $prefix = ""; + + if(count($this->currSib)) + { + $last = array_pop($this->currSib); + + foreach($this->currSib as $sibling) + { + $prefix .= ($sibling) ? $this->getImage("tree_line.gif") : $this->getImage("tree_blank.png"); + } + + $prefix .= ($last) ? $this->getImage("tree_end.gif") : $this->getImage("tree_mid.gif"); + } + + return $prefix; + } + + /** + * Returns a string for the current corpus element which can be used as a HTML class + * property. If the current node is a channel spacer the class string will contain + * additional class names to allow further customization of the content via CSS. + * + * @return string + */ + protected function getCorpusClass() + { + $extras = ""; + + if($this->currObj instanceof TeamSpeak3_Node_Channel && $this->currObj->isSpacer()) + { + switch($this->currObj->spacerGetType()) + { + case (string) TeamSpeak3::SPACER_SOLIDLINE: + $extras .= " solidline"; + break; + + case (string) TeamSpeak3::SPACER_DASHLINE: + $extras .= " dashline"; + break; + + case (string) TeamSpeak3::SPACER_DASHDOTLINE: + $extras .= " dashdotline"; + break; + + case (string) TeamSpeak3::SPACER_DASHDOTDOTLINE: + $extras .= " dashdotdotline"; + break; + + case (string) TeamSpeak3::SPACER_DOTLINE: + $extras .= " dotline"; + break; + } + + switch($this->currObj->spacerGetAlign()) + { + case TeamSpeak3::SPACER_ALIGN_CENTER: + $extras .= " center"; + break; + + case TeamSpeak3::SPACER_ALIGN_RIGHT: + $extras .= " right"; + break; + + case TeamSpeak3::SPACER_ALIGN_LEFT: + $extras .= " left"; + break; + } + } + + return "corpus " . $this->currObj->getClass(null) . $extras; + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusTitle() + { + if($this->currObj instanceof TeamSpeak3_Node_Server) + { + return "ID: " . $this->currObj->getId() . " | Clients: " . $this->currObj->clientCount() . "/" . $this->currObj["virtualserver_maxclients"] . " | Uptime: " . TeamSpeak3_Helper_Convert::seconds($this->currObj["virtualserver_uptime"]); + } + elseif($this->currObj instanceof TeamSpeak3_Node_Channel && !$this->currObj->isSpacer()) + { + return "ID: " . $this->currObj->getId() . " | Codec: " . TeamSpeak3_Helper_Convert::codec($this->currObj["channel_codec"]) . " | Quality: " . $this->currObj["channel_codec_quality"]; + } + elseif($this->currObj instanceof TeamSpeak3_Node_Client) + { + return "ID: " . $this->currObj->getId() . " | Version: " . TeamSpeak3_Helper_Convert::versionShort($this->currObj["client_version"]) . " | Platform: " . $this->currObj["client_platform"]; + } + elseif($this->currObj instanceof TeamSpeak3_Node_Servergroup || $this->currObj instanceof TeamSpeak3_Node_Channelgroup) + { + return "ID: " . $this->currObj->getId() . " | Type: " . TeamSpeak3_Helper_Convert::groupType($this->currObj["type"]) . " (" . ($this->currObj["savedb"] ? "Permanent" : "Temporary") . ")"; + } + } + + /** + * Returns a HTML img tag which can be used to display the status icon for a + * TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusIcon() + { + if($this->currObj instanceof TeamSpeak3_Node_Channel && $this->currObj->isSpacer()) return; + + return $this->getImage($this->currObj->getIcon() . ".png"); + } + + /** + * Returns a string for the current corpus element which contains the display name + * for the current TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusName() + { + if($this->currObj instanceof TeamSpeak3_Node_Channel && $this->currObj->isSpacer()) + { + if($this->currObj->spacerGetType() != TeamSpeak3::SPACER_CUSTOM) return; + + $string = $this->currObj["channel_name"]->section("]", 1, 99); + + if($this->currObj->spacerGetAlign() == TeamSpeak3::SPACER_ALIGN_REPEAT) + { + $string->resize(30, $string); + } + + return htmlspecialchars($string); + } + + if($this->currObj instanceof TeamSpeak3_Node_Client) + { + $before = array(); + $behind = array(); + + foreach($this->currObj->memberOf() as $group) + { + if($group->getProperty("namemode") == TeamSpeak3::GROUP_NAMEMODE_BEFORE) + { + $before[] = "[" . htmlspecialchars($group["name"]) . "]"; + } + elseif($group->getProperty("namemode") == TeamSpeak3::GROUP_NAMEMODE_BEHIND) + { + $behind[] = "[" . htmlspecialchars($group["name"]) . "]"; + } + } + + return implode("", $before) . " " . htmlspecialchars($this->currObj) . " " . implode("", $behind); + } + + return htmlspecialchars($this->currObj); + } + + /** + * Returns a string for the current suffix element which can be used as a HTML + * class property. + * + * @return string + */ + protected function getSuffixClass() + { + return "suffix " . $this->currObj->getClass(null); + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getSuffixIcon() + { + if($this->currObj instanceof TeamSpeak3_Node_Server) + { + return $this->getSuffixIconServer(); + } + elseif($this->currObj instanceof TeamSpeak3_Node_Channel) + { + return $this->getSuffixIconChannel(); + } + elseif($this->currObj instanceof TeamSpeak3_Node_Client) + { + return $this->getSuffixIconClient(); + } + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Server object. + * + * @return string + */ + protected function getSuffixIconServer() + { + $html = ""; + + if($this->currObj["virtualserver_icon_id"]) + { + if(!$this->currObj->iconIsLocal("virtualserver_icon_id") && $this->ftclient) + { + if(!isset($this->cacheIcon[$this->currObj["virtualserver_icon_id"]])) + { + $download = $this->currObj->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->currObj->iconGetName("virtualserver_icon_id")); + + if($this->ftclient == "data:image") + { + $download = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"])->download($download["ftkey"], $download["size"]); + } + + $this->cacheIcon[$this->currObj["virtualserver_icon_id"]] = $download; + } + else + { + $download = $this->cacheIcon[$this->currObj["virtualserver_icon_id"]]; + } + + if($this->ftclient == "data:image") + { + $html .= $this->getImage("data:" . TeamSpeak3_Helper_Convert::imageMimeType($download) . ";base64," . base64_encode($download), "Server Icon", null, FALSE); + } + else + { + $html .= $this->getImage($this->ftclient . "?ftdata=" . base64_encode(serialize($download)), "Server Icon", null, FALSE); + } + } + elseif(in_array($this->currObj["virtualserver_icon_id"], $this->cachedIcons)) + { + $html .= $this->getImage("group_icon_" . $this->currObj["virtualserver_icon_id"] . ".png", "Server Icon"); + } + } + + return $html; + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Channel object. + * + * @return string + */ + protected function getSuffixIconChannel() + { + if($this->currObj instanceof TeamSpeak3_Node_Channel && $this->currObj->isSpacer()) return; + + $html = ""; + + if($this->currObj["channel_flag_default"]) + { + $html .= $this->getImage("channel_flag_default.png", "Default Channel"); + } + + if($this->currObj["channel_flag_password"]) + { + $html .= $this->getImage("channel_flag_password.png", "Password-protected"); + } + + if($this->currObj["channel_codec"] == TeamSpeak3::CODEC_CELT_MONO || $this->currObj["channel_codec"] == TeamSpeak3::CODEC_OPUS_MUSIC) + { + $html .= $this->getImage("channel_flag_music.png", "Music Codec"); + } + + if($this->currObj["channel_needed_talk_power"]) + { + $html .= $this->getImage("channel_flag_moderated.png", "Moderated"); + } + + if($this->currObj["channel_icon_id"]) + { + if(!$this->currObj->iconIsLocal("channel_icon_id") && $this->ftclient) + { + if(!isset($this->cacheIcon[$this->currObj["channel_icon_id"]])) + { + $download = $this->currObj->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->currObj->iconGetName("channel_icon_id")); + + if($this->ftclient == "data:image") + { + $download = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"])->download($download["ftkey"], $download["size"]); + } + + $this->cacheIcon[$this->currObj["channel_icon_id"]] = $download; + } + else + { + $download = $this->cacheIcon[$this->currObj["channel_icon_id"]]; + } + + if($this->ftclient == "data:image") + { + $html .= $this->getImage("data:" . TeamSpeak3_Helper_Convert::imageMimeType($download) . ";base64," . base64_encode($download), "Channel Icon", null, FALSE); + } + else + { + $html .= $this->getImage($this->ftclient . "?ftdata=" . base64_encode(serialize($download)), "Channel Icon", null, FALSE); + } + } + elseif(in_array($this->currObj["channel_icon_id"], $this->cachedIcons)) + { + $html .= $this->getImage("group_icon_" . $this->currObj["channel_icon_id"] . ".png", "Channel Icon"); + } + } + + return $html; + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Client object. + * + * @return string + */ + protected function getSuffixIconClient() + { + $html = ""; + + if($this->currObj["client_is_priority_speaker"]) + { + $html .= $this->getImage("client_priority.png", "Priority Speaker"); + } + + if($this->currObj["client_is_channel_commander"]) + { + $html .= $this->getImage("client_cc.png", "Channel Commander"); + } + + if($this->currObj["client_is_talker"]) + { + $html .= $this->getImage("client_talker.png", "Talk Power granted"); + } + elseif($cntp = $this->currObj->getParent()->channelGetById($this->currObj["cid"])->channel_needed_talk_power) + { + if($cntp > $this->currObj["client_talk_power"]) + { + $html .= $this->getImage("client_mic_muted.png", "Insufficient Talk Power"); + } + } + + foreach($this->currObj->memberOf() as $group) + { + if(!$group["iconid"]) continue; + + $type = ($group instanceof TeamSpeak3_Node_Servergroup) ? "Server Group" : "Channel Group"; + + if(!$group->iconIsLocal("iconid") && $this->ftclient) + { + if(!isset($this->cacheIcon[$group["iconid"]])) + { + $download = $group->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $group->iconGetName("iconid")); + + if($this->ftclient == "data:image") + { + $download = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"])->download($download["ftkey"], $download["size"]); + } + + $this->cacheIcon[$group["iconid"]] = $download; + } + else + { + $download = $this->cacheIcon[$group["iconid"]]; + } + + if($this->ftclient == "data:image") + { + $html .= $this->getImage("data:" . TeamSpeak3_Helper_Convert::imageMimeType($download) . ";base64," . base64_encode($download), $group . " [" . $type . "]", null, FALSE); + } + else + { + $html .= $this->getImage($this->ftclient . "?ftdata=" . base64_encode(serialize($download)), $group . " [" . $type . "]", null, FALSE); + } + } + elseif(in_array($group["iconid"], $this->cachedIcons)) + { + $html .= $this->getImage("group_icon_" . $group["iconid"] . ".png", $group . " [" . $type . "]"); + } + } + + if($this->currObj["client_icon_id"]) + { + if(!$this->currObj->iconIsLocal("client_icon_id") && $this->ftclient) + { + if(!isset($this->cacheIcon[$this->currObj["client_icon_id"]])) + { + $download = $this->currObj->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->currObj->iconGetName("client_icon_id")); + + if($this->ftclient == "data:image") + { + $download = TeamSpeak3::factory("filetransfer://" . (strstr($download["host"], ":") !== FALSE ? "[" . $download["host"] . "]" : $download["host"]) . ":" . $download["port"])->download($download["ftkey"], $download["size"]); + } + + $this->cacheIcon[$this->currObj["client_icon_id"]] = $download; + } + else + { + $download = $this->cacheIcon[$this->currObj["client_icon_id"]]; + } + + if($this->ftclient == "data:image") + { + $html .= $this->getImage("data:" . TeamSpeak3_Helper_Convert::imageMimeType($download) . ";base64," . base64_encode($download), "Client Icon", null, FALSE); + } + else + { + $html .= $this->getImage($this->ftclient . "?ftdata=" . base64_encode(serialize($download)), "Client Icon", null, FALSE); + } + } + elseif(in_array($this->currObj["client_icon_id"], $this->cachedIcons)) + { + $html .= $this->getImage("group_icon_" . $this->currObj["client_icon_id"] . ".png", "Client Icon"); + } + } + + return $html; + } + + /** + * Returns a HTML img tag which can be used to display the country flag for a + * TeamSpeak_Node_Client object. + * + * @return string + */ + protected function getSuffixFlag() + { + if(!$this->currObj instanceof TeamSpeak3_Node_Client) return; + + if($this->flagpath && $this->currObj["client_country"]) + { + return $this->getImage($this->currObj["client_country"]->toLower() . ".png", $this->currObj["client_country"], null, FALSE, TRUE); + } + } + + /** + * Returns the code to display a custom HTML img tag. + * + * @param string $name + * @param string $text + * @param string $class + * @param boolean $iconpath + * @param boolean $flagpath + * @return string + */ + protected function getImage($name, $text = "", $class = null, $iconpath = TRUE, $flagpath = FALSE) + { + $src = ""; + + if($iconpath) + { + $src = $this->iconpath; + } + + if($flagpath) + { + $src = $this->flagpath; + } + + return ""; + } +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Viewer/Interface.php b/lib/ts3phpframework/libraries/TeamSpeak3/Viewer/Interface.php new file mode 100644 index 0000000..62eed20 --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Viewer/Interface.php @@ -0,0 +1,42 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Viewer_Interface + * @brief Interface class describing a TeamSpeak 3 viewer. + */ +interface TeamSpeak3_Viewer_Interface +{ + /** + * Returns the code needed to display a node in a TeamSpeak 3 viewer. + * + * @param TeamSpeak3_Node_Abstract $node + * @param array $siblings + * @return string + */ + public function fetchObject(TeamSpeak3_Node_Abstract $node, array $siblings = array()); +} diff --git a/lib/ts3phpframework/libraries/TeamSpeak3/Viewer/Text.php b/lib/ts3phpframework/libraries/TeamSpeak3/Viewer/Text.php new file mode 100644 index 0000000..eecd5ee --- /dev/null +++ b/lib/ts3phpframework/libraries/TeamSpeak3/Viewer/Text.php @@ -0,0 +1,107 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.24 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Viewer_Text + * @brief Renders nodes used in ASCII-based TeamSpeak 3 viewers. + */ +class TeamSpeak3_Viewer_Text implements TeamSpeak3_Viewer_Interface +{ + /** + * A pre-defined pattern used to display a node in a TeamSpeak 3 viewer. + * + * @var string + */ + protected $pattern = "%0%1 %2\n"; + + /** + * Returns the code needed to display a node in a TeamSpeak 3 viewer. + * + * @param TeamSpeak3_Node_Abstract $node + * @param array $siblings + * @return string + */ + public function fetchObject(TeamSpeak3_Node_Abstract $node, array $siblings = array()) + { + $this->currObj = $node; + $this->currSib = $siblings; + + $args = array( + $this->getPrefix(), + $this->getCorpusIcon(), + $this->getCorpusName(), + ); + + return TeamSpeak3_Helper_String::factory($this->pattern)->arg($args); + } + + /** + * Returns the ASCII string to display the prefix of the current node. + * + * @return string + */ + protected function getPrefix() + { + $prefix = ""; + + if(count($this->currSib)) + { + $last = array_pop($this->currSib); + + foreach($this->currSib as $sibling) + { + $prefix .= ($sibling) ? "| " : " "; + } + + $prefix .= ($last) ? "\\-" : "|-"; + } + + return $prefix; + } + + /** + * Returns an ASCII string which can be used to display the status icon for a + * TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusIcon() + { + return $this->currObj->getSymbol(); + } + + /** + * Returns a string for the current corpus element which contains the display name + * for the current TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusName() + { + return $this->currObj; + } +} diff --git a/news/README.txt b/news/README.txt new file mode 100644 index 0000000..5367c22 --- /dev/null +++ b/news/README.txt @@ -0,0 +1,15 @@ +Informacje na temat systemu newsów: + +Jeśli chcesz, możesz dodawać, zmieniać oraz usuwać newsy w domyślnym folderze news. Folder ten jest do zmiany w pliku config.php +Aktualnie newsy są tworzone przy użyciu Markdown mieszanego z HTMLem. Może potem dodam jakiś panel jak mi się zachcę Xd + +Prosty poradnik na temat Markdown od GitHuba: https://guides.github.com/features/mastering-markdown/ + +Przydatne informacje: +- Newsy wczytywane są z folderu w kolejności alfabetycznej +- Każdy plik z newsami musi mieć rozszerzenie .md (Markdown) +- Format plikow z newsami: + - Pierwsza linijka: tytuł newsa + - Druga linijka: autor i data + - Trzecia linijka: pusta (taki seperator) + - Reszta pliku: treść newsa (Markdown + HTML) diff --git a/news/news1.md b/news/news1.md new file mode 100644 index 0000000..e9ed224 --- /dev/null +++ b/news/news1.md @@ -0,0 +1,14 @@ +Informacje na temat systemu newsów +Wruczek, 2016-06-24, 21:00 + +Jeśli chcesz, możesz dodawać, zmieniać oraz usuwać newsy w domyślnym folderze news. Folder ten możesz zmienić w pliku config.php +Aktualnie newsy są tworzone przy użyciu Markdown mieszanego z HTMLem. Może potem dodam jakiś panel, a na razie polecam [prosty poradnik na temat Markdown od GitHuba](https://guides.github.com/features/mastering-markdown/). + +Przydatne informacje: +- Newsy wczytywane są z folderu w kolejności alfabetycznej +- Każdy plik z newsami musi mieć rozszerzenie .md (Markdown) +- Format plikow z newsami: + - Pierwsza linijka: tytuł newsa + - Druga linijka: autor i data + - Trzecia linijka: pusta (taki seperator) + - Reszta pliku: treść newsa (Markdown + HTML) diff --git a/news/news2.md b/news/news2.md new file mode 100644 index 0000000..096d819 --- /dev/null +++ b/news/news2.md @@ -0,0 +1,378 @@ +Readme od jQuery - do testów systemu +jQuery, 2016-06-24, 21:00 + +[jQuery](https://jquery.com/) — New Wave JavaScript +================================================== + +Contribution Guides +-------------------------------------- + +In the spirit of open source software development, jQuery always encourages community code contribution. To help you get started and before you jump into writing code, be sure to read these important contribution guidelines thoroughly: + +1. [Getting Involved](https://contribute.jquery.org/) +2. [Core Style Guide](https://contribute.jquery.org/style-guide/js/) +3. [Writing Code for jQuery Foundation Projects](https://contribute.jquery.org/code/) + + +Environments in which to use jQuery +-------------------------------------- + +- [Browser support](https://jquery.com/browser-support/) +- jQuery also supports Node, browser extensions, and other non-browser environments. + + +What you need to build your own jQuery +-------------------------------------- + +In order to build jQuery, you need to have the latest Node.js/npm and git 1.7 or later. Earlier versions might work, but are not supported. + +For Windows, you have to download and install [git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/en/download/). + +OS X users should install [Homebrew](http://brew.sh/). Once Homebrew is installed, run `brew install git` to install git, +and `brew install node` to install Node.js. + +Linux/BSD users should use their appropriate package managers to install git and Node.js, or build from source +if you swing that way. Easy-peasy. + + +How to build your own jQuery +---------------------------- + +Clone a copy of the main jQuery git repo by running: + +```bash +git clone git://github.com/jquery/jquery.git +``` + +Enter the jquery directory and run the build script: +```bash +cd jquery && npm run build +``` +The built version of jQuery will be put in the `dist/` subdirectory, along with the minified copy and associated map file. + +If you want to create custom build or help with jQuery development, it would be better to install [grunt command line interface](https://github.com/gruntjs/grunt-cli) as a global package: + +``` +npm install -g grunt-cli +``` +Make sure you have `grunt` installed by testing: +``` +grunt -V +``` + +Now by running the `grunt` command, in the jquery directory, you can build a full version of jQuery, just like with an `npm run build` command: +``` +grunt +``` + +There are many other tasks available for jQuery Core: +``` +grunt -help +``` + +### Modules + +Special builds can be created that exclude subsets of jQuery functionality. +This allows for smaller custom builds when the builder is certain that those parts of jQuery are not being used. +For example, an app that only used JSONP for `$.ajax()` and did not need to calculate offsets or positions of elements could exclude the offset and ajax/xhr modules. + +Any module may be excluded except for `core`, and `selector`. To exclude a module, pass its path relative to the `src` folder (without the `.js` extension). + +Some example modules that can be excluded are: + +- **ajax**: All AJAX functionality: `$.ajax()`, `$.get()`, `$.post()`, `$.ajaxSetup()`, `.load()`, transports, and ajax event shorthands such as `.ajaxStart()`. +- **ajax/xhr**: The XMLHTTPRequest AJAX transport only. +- **ajax/script**: The `