Initial import from revision 11440

This commit is contained in:
NightOath 2011-03-28 15:21:28 +01:00
commit ff67a811d4
1125 changed files with 74100 additions and 0 deletions

150
CHANGES.txt Normal file
View File

@ -0,0 +1,150 @@
CHANGELOG
2010-08-28
-Upgrade Sphinx to 1.10b
2010-08-25
-Better handling of special characters in torrent searches
-Improved file name search
-Add negations to request searches
2010-08-11
-Fixed long standing IE Bug. Turns out that IE fails to handle unicode data in the Content-disposition header so this value is now urlencoded ensuring compatibility.
2010-08-10
-Added check for CustomPerms IP protection on login
2010-07-30
-Add collage stats to user profiles
2010-07-04
-Updated sphinx.conf
2010-06-26
-Fixed IP bans and added to public repo
-Added catch for missing system 'host' command
-Logged in users can't hit register.php
-Fix in URL_REGEX to allow URLs of the form http://foo.com/
2010-06-09
-Delete torrent files when torrent is deleted
2010-06-04
-User proper names on bookmark/notify links if a group is already bookmarked or in the notifications
2010-05-21
-Sortable invitee list
2010-05-16
-Escape tag links on user torrent pages
2010-05-12
-Make the "view tags" button change to "hide tags" if tags are shown
-Make editing upload/download amounts work on 32bit systems
-Fix a typo in class_cache, not major
-Add default values to schedule table
2010-05-09
-Add catchup link to subscriptions page
2010-05-05
-Move $Classes fetching code to somewhere globally accessible so that schedule can fetch it
2010-05-03
-Fixed bug in 32bit parser that would allow clients to set private=0
2010-05-01
-Add preview functionality to thread creation page
2010-04-30
-Fix various subscription bugs
2010-04-29
-Properly update cache and database when a forum post is removed
2010-04-28
-Alias IDs now show next to artists in the artist box
-Users with an infinite ratio now get promoted along with those who have a
ratio of 1.05 or higher
2010-04-26
-Fixed bug where snatchlists were not visible to other users at paranoia level
1 (should be 2 or higher)
2010-04-19
-Add requests to sphinx.conf
2010-04-18
-Fix request sorting
2010-04-15
-Added clickable staff notes
2010-04-14
-Add stylesheet and avatar search to advanced user search
2010-04-13
-Require authorization to manually run schedule
-Fix minor bbcode bug which didn't allow question marks in filenames
2010-04-11
-Add "visible" checkbox to user profiles. Unticked, this will remove a user from a peer list.
-Add option to disable PM privileges of user
2010-04-07
-Fix critical bug where users can view staff forum posts by changing the ID on the reports page
2010-03-18
-Clear notifications per torrent or filter
2010-03-16
-Notifications groups actually work now
-Post history and subscriptions pages now default to unread posts with collapsed post bodies
2010-03-14
-Group notifications by filter
2010-03-13
-Added ability to view a user's downloaded torrents as well as snatched
2010-03-12
-Thread subscriptions
-Various bugfixes, see resolved gazelle bug forum
-Standardised Email and Image regexes across gazelle
2010-03-10
-Completed requestsv2, feel free to use it now
2010-03-09
-Add size and files column to notifications page and clone the browse layout
-Don't redirect if ssl url == nonssl url
-Fix some more warnings when calling sphinxapi.php
-Year filter in notifications also checks remaster year
2010-03-07
-Change INSERT INTO to REPLACE INTO to avoid errors when updating the sphinx*_delta tables
2010-03-04
-Added initial version of requestsv2, will need more updates so not advised to
update yet
2010-03-02
-Fixed bug in notifications by tags
2010-03-01
-Fixed bug in notifications by release type
2010-02-28
-Fixed bug which causes stats to be altered if the tracker updates while someone with stat editing powers moderates a profile
-Fixed artist permission
-Fixed two permission bugs
-Removed references to What.CD in takemoderate.php
-Fixed E_NOTICE with regards to taglist on browse2.php
-Removed geodistribution from stats, fixed stats so they don't whitepage
-Fixed the user geodistribution stats and geoip database updater, and added a function for an unsigned ip2long
-Kill poll manager, it doesn't work anymore - use the forums
-Fix width of poll replies, don't display poll if there aren't any
-Re-add reports folder
-Fixed "database schema" tool
-Fix upscale pool blank message
-Fix number of posts in a forum after a thread has been moved out of it
-Strip out SVN revision echo

133
COPYING.txt Normal file
View File

@ -0,0 +1,133 @@
COPYRIGHTED AND PATENTED PENDING BY WHAT.CD INCORPORATED, DBA/AKA PROJECT
GAZELLE
END-USER LICENSE AGREEMENT
The Gazelle Source Code (hereinafter referred to as the Software) is made
publically available free of charge by Project Gazelle (sometimes a trade and
business name for the legally consituted entity known as What.CD Incorporated,
a Panamanian Corporation), copyright and patent pending owner (hereinafter
referred to as the Licensor or Original Licensor) to anyone who wishes to use
and/or share or distribute and/or change or modify it (hereinafter referred to
as either the Licensee and/or End-User) FOR NONCOMMERCIAL PURPOSES ONLY under
the following terms and conditions (hereinafter referred to as the "License"):
Section 1. You may copy and distribute verbatim copies of the Software's
source code as you receive it, in any medium, provided that you conspicuously
and appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this License
and to the absence of any warranty; and give any other recipients of the
Software a copy of this License along with the Software.
Section 2: You may modify or change your copy or copies of the Software or
any portion of it, thus forming a work based on the Software, and copy and
distribute such modifications or work under the terms of Section 1 above,
provided that you also meet all of these conditions:
2.1: You must cause the modified files to carry prominent notices stating
that you changed the files and the date of any change.
2.2: You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Software or any part thereof,
to be licensed as a whole at no charge to all third parties under the terms of
this License.
Section 3: You may copy and distribute the Software (or a work based on it,
under the terms of Section 2) in object code or executable form under the
terms of Sections 1 and 2 above provided that you also do one of the
following:
3.1: Accompany it with the complete corresponding machine-readable source
code, which must be distributed under the terms of Sections 1 and 2 above on
a medium customarily used for software interchange; or,
3.2: Accompany it with a written offer, valid for at least one year, to
give any third party, for a charge no more than your cost of physically
performing source distribution, a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of Sections 1 and
2 above on a medium customarily used for software interchange; or,
3.3: Accompany it with the information you received as to the offer to
distribute corresponding source code. (This alternative is allowed only for
noncommercial distribution and only if you received the Software in object
code or executable form with such an offer, in accord with Subsection 3.2
above.)
Section 4: You may not copy, modify, sublicense, or distribute the Software
except as expressly provided under this License. Any attempt otherwise to
copy, modify, sublicense or distribute the Software is void, and will
automatically terminate your rights under this License. Parties who have
received copies, or rights, from you under this License, however, will not
have their licenses terminated so long as such parties remain in full
compliance with the terms and conditions of this License.
Section 5: This License and nothing else grants you permission to use, modify
and/or distribute the Software or its derivative works and only in accordance
with the terms and conditions of this License. Otherwise, use, modification
and/or distribution of this Software is prohibited by international laws and
treaties as regards intellectual property. Therefore, by using, modifying
and/or distributing the Software (or any work based on the Software), you
indicate your acceptance of this License to do so, and all its terms and
conditions for copying, distributing or modifying the software or works based
on it.
Section 6: Each time you redistribute the Software (or any work based on the
Software), the recipient automatically receives a license from the Original
Licensor to copy, distribute and/or modify the Software subject to these terms
and conditions. You may not impose any further restrictions on the
recipients' exercise of the rights granted herein. You are not responsible for
enforcing compliance by third parties to this License.
Section 7: NO WARRANTY
7.1: BECAUSE THE SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT
WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT/PATENT HOLDERS AND/OR OTHER
PARTIES PROVIDE THE SOFTWARE "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 SOFTWARE IS WITH YOU. SHOULD THE PROGRAM
PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
CORRECTION.
7.2:. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT/PATENT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE SOFTWARE 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 SOFTWARE TO OPERATE WITH ANY OTHER
SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
Section 8: If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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 distribute so as to satisfy
simultaneously your obligations under this License and any other pertinent
obligations, then as a consequence you may not distribute the Software at all.
For example, if a patent license would not permit royalty-free redistribution
of the Software by all those who receive copies directly or indirectly through
you, then the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Software.
Section 9: If any portion or section of this License is held invalid or
unenforceable under any particular circumstance, the balance of this License
and pertinent section is intended to apply and the section as a whole is
intended to apply in other circumstances.
Section 10: Each version of the Software is given a distinguishing version
number. If the Software specifies a version number of this License which
applies to it and "any later version", you have the option of following the
terms and conditions either of that version or of any later version. If the
Software does not specify a version number of this License, you may choose any
version ever published by the Licensor.
Section 11: This Software is distributed pursuant to the terms and conditions
of this License and is distributed free of charge FOR NONCOMMERCIAL PURPOSES
ONLY. THE USE, DISTRIBUTION AND/OR MODIFICATION OF THIS SOFTWARE FOR
COMMERCIAL PURPOSES IS EXPRESSLY PROHIBITED BY INTERNATIONAL LAWS AND TREATIES
AS REGARDS INTELLECTUAL PROPERTY.

30
INSTALL.txt Normal file
View File

@ -0,0 +1,30 @@
INSTALLATION NOTES
1. Set up MySQL and memcached. We run memcached with the command:
memcached -d -m 5120 -s /var/run/memcached.sock -a 0777 -t16 -C -u root
This gives it 5 gigs of RAM, you probably want to set that a bit lower!
2. Run gazelle.sql (preferably as root) to create the database, the table, and the default data.
3. Install sphinx - we recommend you use the included sphinx.conf
For documentation, read http://www.sphinxsearch.com/docs/current.html
After you've installed, create the indices:
/usr/local/bin/indexer -c /etc/sphinx/sphinx.conf --all
4. Move classes/config.template to classes/config.php. Edit the config.php as needed.
We use http://grc.com/passwords.html for our passwords - you'll be generating a lot of these.
5. Sign up. The first user is made a sysop!
6. Set up cron jobs. You need a cron job for the schedule, a cron job for
the peerupdate (all groups are cached, but the peer counts change often,
so peerupdate is a script to update them), and the two sphinx indices.
These are our cron jobs:
0,15,30,45 * * * * /usr/local/bin/php /var/www/vhosts/what/schedule.php SCHEDULE_KEY >> /root/schedule.log
10,25,40,55 * * * * /usr/local/bin/php /var/www/vhosts/what/peerupdate.php SCHEDULE_KEY >> /root/peerupdate.log
* * * * * /usr/local/bin/indexer -c /etc/sphinx/sphinx.conf --rotate delta
5 0,12 * * * /usr/local/bin/indexer -c /etc/sphinx/sphinx.conf --rotate --all
7. You're probably going to want geoip information, so first you need to fill in the geoip_country tables by visiting /tools.php?action=update_geoip .
After that finishes parsing information from maxmind, you'll may want to map users to countries by running:
"INSERT INTO users_geodistribution (Code, Users) SELECT g.Code, COUNT(u.ID) AS Users FROM geoip_country AS g JOIN users_main AS u ON INET_ATON(u.IP) BETWEEN g.StartIP AND g.EndIP WHERE u.Enabled='1' GROUP BY g.Code ORDER BY Users DESC"
This will fill in the table needed for stats.
8. Start modifying stuff. Hopefully, everything will have gone smoothly so far and nothing will have exploded (ha ha ha)

1
ajax.php Normal file
View File

@ -0,0 +1 @@
<? require('classes/script_start.php'); ?>

1
announce.php Normal file
View File

@ -0,0 +1 @@
d14:failure reason40:Invalid .torrent, try downloading again.e

116
api.php Normal file
View File

@ -0,0 +1,116 @@
<?
/*-- API Start Class -----------------------------------*/
/*------------------------------------------------------*/
/* Simplified version of script_start, used for the */
/* site API calls */
/*------------------------------------------------------*/
/********************************************************/
$ScriptStartTime=microtime(true); //To track how long a page takes to create
//Lets prevent people from clearing feeds
if (isset($_GET['clearcache'])) {
unset($_GET['clearcache']);
}
require 'classes/config.php'; //The config contains all site wide configuration information as well as memcached rules
require(SERVER_ROOT.'/classes/class_cache.php'); //Require the caching class
require(SERVER_ROOT.'/classes/class_debug.php'); //Require the debug class
$Cache = NEW CACHE; //Load the caching class
$Debug = new DEBUG;
$Debug->handle_errors();
// Send a message to an IRC bot listening on SOCKET_LISTEN_PORT
function send_irc($Raw) {
$IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT);
fwrite($IRCSocket, $Raw);
fclose($IRCSocket);
}
function check_perms() {
return false;
}
function error($Code) {
echo '<error>',$Code,'</error></payload>';
die();
}
function make_secret($Length = 32) {
$Secret = '';
$Chars='abcdefghijklmnopqrstuvwxyz0123456789';
for($i=0; $i<$Length; $i++) {
$Rand = mt_rand(0, strlen($Chars)-1);
$Secret .= substr($Chars, $Rand, 1);
}
return str_shuffle($Secret);
}
function is_number($Str) {
if ($Str < 0) { return false; }
// We're converting input to a int, then string and comparing to original
return ($Str == strval(intval($Str)) ? true : false);
}
function display_str($Str) {
if ($Str!="") {
$Str=make_utf8($Str);
$Str=mb_convert_encoding($Str,"HTML-ENTITIES","UTF-8");
$Str=preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m","&amp;",$Str);
$Replace = array(
"'",'"',"<",">",
'&#128;','&#130;','&#131;','&#132;','&#133;','&#134;','&#135;','&#136;','&#137;','&#138;','&#139;','&#140;','&#142;','&#145;','&#146;','&#147;','&#148;','&#149;','&#150;','&#151;','&#152;','&#153;','&#154;','&#155;','&#156;','&#158;','&#159;'
);
$With=array(
'&#39;','&quot;','&lt;','&gt;',
'&#8364;','&#8218;','&#402;','&#8222;','&#8230;','&#8224;','&#8225;','&#710;','&#8240;','&#352;','&#8249;','&#338;','&#381;','&#8216;','&#8217;','&#8220;','&#8221;','&#8226;','&#8211;','&#8212;','&#732;','&#8482;','&#353;','&#8250;','&#339;','&#382;','&#376;'
);
$Str=str_replace($Replace,$With,$Str);
}
return $Str;
}
function make_utf8($Str) {
if ($Str!="") {
if (is_utf8($Str)) { $Encoding="UTF-8"; }
if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); }
if (empty($Encoding)) { $Encoding="ISO-8859-1"; }
if ($Encoding=="UTF-8") { return $Str; }
else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); }
}
}
function is_utf8($Str) {
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] // ASCII
| [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16
)*$%xs', $Str
);
}
function display_array($Array, $Escape = array()) {
foreach ($Array as $Key => $Val) {
if((!is_array($Escape) && $Escape == true) || !in_array($Key, $Escape)) {
$Array[$Key] = display_str($Val);
}
}
return $Array;
}
header('Expires: '.date('D, d M Y H:i:s', time()+(2*60*60)).' GMT');
header('Last-Modified: '.date('D, d M Y H:i:s').' GMT');
header('Content-type: text/xml');
echo '<?xml version="1.0"?><payload>';
require(SERVER_ROOT.'/sections/api/index.php');
?>

5
artist.php Normal file
View File

@ -0,0 +1,5 @@
<?
define('ERROR_EXCEPTION', true);
require('classes/script_start.php');

3
better.php Normal file
View File

@ -0,0 +1,3 @@
<?
define('ERROR_EXCEPTION', true);
require('classes/script_start.php');

0
block_04097.html Normal file
View File

1
blog.php Normal file
View File

@ -0,0 +1 @@
<? require('classes/script_start.php');

3
bookmarks.php Normal file
View File

@ -0,0 +1,3 @@
<?
define('ERROR_EXCEPTION', true);
require('classes/script_start.php');

1
browse.php Normal file
View File

@ -0,0 +1 @@
<? header('Location: torrents.php');

1
captcha.php Normal file
View File

@ -0,0 +1 @@
<? require("classes/script_start.php");

BIN
captcha/captcha1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
captcha/captcha2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
captcha/captcha3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
captcha/captcha4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
captcha/captcha5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
captcha/captcha6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
captcha/captcha7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
captcha/captcha8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
captcha/captcha9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

2
chat.php Normal file
View File

@ -0,0 +1,2 @@
<? require("classes/script_start.php");

2
cheaters.php Normal file
View File

@ -0,0 +1,2 @@
<?
require('classes/script_start.php');

91
classes/ajax_start.php Normal file
View File

@ -0,0 +1,91 @@
<?
require 'config.php'; //The config contains all site wide configuration information as well as memcached rules
require(SERVER_ROOT.'/classes/class_cache.php'); //Require the caching class
require(SERVER_ROOT.'/classes/class_encrypt.php'); //Require the caching class
$Cache = NEW CACHE; //Load the caching class
$Enc = NEW CRYPT; //Load the encryption class
$SSL = ($_SERVER['SERVER_PORT'] === '443');
if (isset($_COOKIE['session'])) { $LoginCookie=$Enc->decrypt($_COOKIE['session']); }
if(isset($LoginCookie)) {
list($SessionID, $UserID)=explode("|~|",$Enc->decrypt($LoginCookie));
if(!$UserID || !$SessionID) {
die('Not logged in!');
}
if(!$Enabled = $Cache->get_value('enabled_'.$UserID)){
require(SERVER_ROOT.'/classes/class_mysql.php'); //Require the database wrapper
$DB=NEW DB_MYSQL; //Load the database wrapper
$DB->query("SELECT Enabled FROM users_main WHERE ID='$UserID'");
list($Enabled) = $DB->next_record();
$Cache->cache_value('enabled_'.$UserID, $Enabled, 0);
}
} else {
die('Not logged in!');
}
function error($Error) {
die($Error);
}
function is_number($Str) {
if ($Str < 0) { return false; }
// We're converting input to a int, then string and comparing to original
return ($Str == strval(intval($Str)) ? true : false);
}
function display_str($Str) {
if ($Str!="") {
$Str=make_utf8($Str);
$Str=mb_convert_encoding($Str,"HTML-ENTITIES","UTF-8");
$Str=preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m","&amp;",$Str);
$Replace = array(
"'",'"',"<",">",
'&#128;','&#130;','&#131;','&#132;','&#133;','&#134;','&#135;','&#136;','&#137;','&#138;','&#139;','&#140;','&#142;','&#145;','&#146;','&#147;','&#148;','&#149;','&#150;','&#151;','&#152;','&#153;','&#154;','&#155;','&#156;','&#158;','&#159;'
);
$With=array(
'&#39;','&quot;','&lt;','&gt;',
'&#8364;','&#8218;','&#402;','&#8222;','&#8230;','&#8224;','&#8225;','&#710;','&#8240;','&#352;','&#8249;','&#338;','&#381;','&#8216;','&#8217;','&#8220;','&#8221;','&#8226;','&#8211;','&#8212;','&#732;','&#8482;','&#353;','&#8250;','&#339;','&#382;','&#376;'
);
$Str=str_replace($Replace,$With,$Str);
}
return $Str;
}
function make_utf8($Str) {
if ($Str!="") {
if (is_utf8($Str)) { $Encoding="UTF-8"; }
if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); }
if (empty($Encoding)) { $Encoding="ISO-8859-1"; }
if ($Encoding=="UTF-8") { return $Str; }
else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); }
}
}
function is_utf8($Str) {
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] // ASCII
| [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16
)*$%xs', $Str
);
}
function display_array($Array, $DontEscape = array()) {
foreach ($Array as $Key => $Val) {
if(!in_array($Key, $DontEscape)) {
$Array[$Key] = display_str($Val);
}
}
return $Array;
}

65
classes/class_alias.php Normal file
View File

@ -0,0 +1,65 @@
<?
class ALIAS {
function convert($str) {
return trim(substr(preg_replace('/[^a-z0-9]/', '', strtolower(htmlentities($str))), 0, 50));
}
//Alternative approach with potential.
function flush() {
global $Cache, $DB;
$DB->query("SELECT Alias, ArticleID FROM wiki_aliases");
$Aliases = $DB->to_array('Alias');
$Cache->cache_value('wiki_aliases', $Aliases, 3600*24*14);
}
function to_id($Alias) {
global $Cache, $DB;
$Aliases = $Cache->get_value('wiki_aliases');
if(!$Aliases){
$DB->query("SELECT Alias, ArticleID FROM wiki_aliases");
$Aliases = $DB->to_array('Alias');
$Cache->cache_value('wiki_aliases', $Aliases, 3600*24*14);
}
return $Aliases[$this->convert($Alias)]['ArticleID'];
}
/*
function flush() {
}
function to_id($Alias) {
global $DB;
$Alias = $this->convert($Alias);
$DB->query("SELECT ArticleID FROM wiki_aliases WHERE Alias LIKE '$Alias'");
list($ArticleID) = $DB->next_record();
return $ArticleID;
}
*/
function article($ArticleID) {
global $Cache, $DB;
$Contents = $Cache->get_value('wiki_article_'.$ArticleID);
if(!$Contents){
$DB->query("SELECT
w.Revision,
w.Title,
w.Body,
w.MinClassRead,
w.MinClassEdit,
w.Date,
w.Author,
u.Username,
GROUP_CONCAT(a.Alias),
GROUP_CONCAT(a.UserID)
FROM wiki_articles AS w
LEFT JOIN wiki_aliases AS a ON w.ID=a.ArticleID
LEFT JOIN users_main AS u ON u.ID=w.Author
WHERE w.ID='$ArticleID'
GROUP BY w.ID");
if(!$DB->record_count()) { error(404); }
$Contents = $DB->to_array();
$Cache->cache_value('wiki_article_'.$ArticleID, $Contents, 3600*24*14);
}
return $Contents;
}
}
?>

19
classes/class_artist.php Normal file
View File

@ -0,0 +1,19 @@
<?
class ARTIST {
var $ID = 0;
var $Name = 0;
var $NameLength = 0;
var $SimilarID = 0;
var $Displayed = false;
var $x = 0;
var $y = 0;
var $Similar = array();
function ARTIST($ID='', $Name=''){
$this->ID = $ID;
$this->NameLength = mb_strlen($Name, 'utf8');
$this->Name = display_str($Name);
}
}
?>

View File

@ -0,0 +1,372 @@
<?
class ARTISTS_SIMILAR extends ARTIST{
var $Artists = array();
var $TotalScore = 0;
var $xValues = array(WIDTH=>1);
var $yValues = array(HEIGHT=>1);
var $LargestDecimal = 0;
var $LowestDecimal = 1;
function dump_data(){
return serialize(array(time(), $this->Name, $this->x, $this->y, serialize($this->Artists), serialize($this->Similar)));
}
function load_data($Data){
list($LastUpdated, $this->Name, $this->x, $this->y, $this->Artists, $this->Similar) = unserialize($Data);
$this->Artists = unserialize($this->Artists);
$this->Similar = unserialize($this->Similar);
}
function set_up(){
$this->x = ceil(WIDTH/2);
$this->y = ceil(HEIGHT/2);
$this->xValues[$this->x] = $this->ID;
$this->yValues[$this->y] = $this->ID;
global $DB;
// Get artists that are directly similar to the artist
$ArtistIDs = array();
$DB->query("
SELECT
s2.ArtistID,
ag.Name,
ass.Score
FROM artists_similar AS s1
JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID
JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID
JOIN artists_group AS ag ON ag.ArtistID=s2.ArtistID
WHERE s1.ArtistID=".$this->ID."
ORDER BY ass.Score DESC
LIMIT 14");
if($DB->record_count() == 0){
return;
}
// Build into array. Each artist is its own object in $this->Artists
while(list($ArtistID, $Name, $Score) = $DB->next_record(MYSQLI_NUM, false)){
if($Score<0){
continue;
}
$this->Artists[$ArtistID] = new ARTIST($ArtistID, $Name);
$this->Similar[$ArtistID] = array('ID'=>$ArtistID,'Score'=>$Score);
$this->TotalScore+=$Score;
$ArtistIDs[]=$ArtistID;
}
// Get similarities between artists on the map
$DB->query("SELECT
s1.ArtistID,
s2.ArtistID
FROM artists_similar AS s1
JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID
JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID
JOIN artists_group AS a ON a.ArtistID=s2.ArtistID
WHERE s1.ArtistID IN(".implode(',',$ArtistIDs).")
AND s2.ArtistID IN(".implode(',',$ArtistIDs).")
");
// Build into array
while(list($Artist1ID, $Artist2ID) = $DB->next_record()){
$this->Artists[$Artist1ID]->Similar[$Artist2ID] = array('ID'=>$Artist2ID);
}
// Calculate decimal point scores between artists
foreach($this->Similar as $SimilarArtist) {
list($ArtistID, $Similar) = array_values($SimilarArtist);
$this->Similar[$ArtistID]['Decimal'] = $this->similarity($Similar['Score'], $this->TotalScore);
if($this->Similar[$ArtistID]['Decimal'] < $this->LowestDecimal){
$this->LowestDecimal = $this->Similar[$ArtistID]['Decimal'];
}
if($this->Similar[$ArtistID]['Decimal'] > $this->LargestDecimal){
$this->LargestDecimal = $this->Similar[$ArtistID]['Decimal'];
}
}
reset($this->Artists);
}
function set_positions(){
$xValues = array(); // Possible x values
$Root = ceil(WIDTH/4); // Half-way into half of the image
$Offset = 4; // Distance from the root (a quarter of the way into the image) to the x value
// The number of artists placed in the top or the bottom
$NumTop = 0;
$NumBottom = 0;
// The number of artists placed in the left or the right
$NumLeft = 0;
$NumRight = 0;
$Multiplier = 0;
// Build up an impressive list of possible x values
// We later iterate through these, and pick out the ones we want
// These x values are all below WIDTH/2 (all on the left)
// The script later chooses which side to put them on
// We create more very low x values because they're more likely to be skipped
for($i = 0; $i<=count($this->Artists)*4; $i++){
if($Offset>=((WIDTH/4))){
$Offset=$Offset%(WIDTH/4);
}
$Plus = $Root+$Offset; // Point on the right of the root
$Minus = abs($Root-$Offset); // Point on the left of the root
$xValues[$Plus]=$Plus;
$xValues[$Minus]=$Minus;
// Throw in an extra x value closer to the edge, because they're more likely to be skipped
if($Minus>30){
// $xValues[$Minus-30]=$Minus-30;
}
$Offset = $Offset+rand(5,20); // Increase offset, and go again
}
foreach($this->Artists as $Artist){
$ArtistID = $Artist->ID;
if($Artist->Displayed == true){
continue;
}
$this->Similar[$ArtistID]['Decimal'] = $this->Similar[$ArtistID]['Decimal'] * (1/($this->LargestDecimal))-0.1;
// Calculate the distance away from the center, based on similarity
$IdealDistance = $this->calculate_distance($this->Similar[$ArtistID]['Decimal'], $this->x, $this->y);
$this->Similar[$ArtistID]['Distance'] = $IdealDistance;
// 1 = left, 2 = right
$Horizontal = 0;
$Vertical = 0;
// See if any similar artists have been placed yet. If so, place artist in that half
// (provided that there are enough in the other half to visually balance out)
reset($Artist->Similar);
foreach($Artist->Similar as $SimilarArtist) {
list($Artist2ID) = array_values($SimilarArtist);
if($this->Artists[$Artist2ID]) {
if($this->Artists[$Artist2ID]->x > (WIDTH/2) && ($NumRight-$NumLeft)<1){
$Horizontal = 2;
} elseif($NumLeft-$NumRight<1) {
$Horizontal = 1;
}
break;
}
}
shuffle($xValues);
while($xValue = array_shift($xValues)){
if(abs($this->x - $xValue) <= $IdealDistance) {
if(hypot(abs($this->x - $xValue), ($this->y - 50)) > $IdealDistance
|| ceil(sqrt(pow($IdealDistance, 2) - pow($this->x - $xValue, 2))) > (HEIGHT/2)){
$xValue = $this->x - ceil(sqrt(pow($IdealDistance, 2) - pow($IdealDistance*0.1*rand(5,9), 2)));
//echo "Had to change x value for ".$Artist->Name." to ".$xValue."\n";
}
// Found a match (Is close enough to the center to satisfy $IdealDistance),
// Now it's time to choose which half to put it on
if(!$Horizontal) {
// No similar artists displayed
$Horizontal = ($NumLeft<$NumRight) ? 1 : 2;
}
if($Horizontal == 2){
$xValue = WIDTH-$xValue;
$NumRight++;
} else {
$NumLeft++;
}
$Artist->x = $xValue;
$this->xValues[$xValue] = $ArtistID;
unset($xValues[$xValue]);
break;
}
}
if(!$xValue){ // Uh-oh, we were unable to choose an x value.
$xValue = ceil(sqrt(pow($IdealDistance, 2)/2));
$xValue = (WIDTH/2)-$xValue;
$Artist->x = $xValue;
$this->xValues[$xValue] = $ArtistID;
unset($xValues[$xValue]);
}
// Pythagoras. $yValue is the vertical distance from the center to the y value
$yValue = sqrt(pow($IdealDistance, 2) - pow(abs($this->x - $Artist->x), 2));
// Now we pick if it should go on the top or bottom
if($NumTop>$NumBottom){ // Send it to the bottom half
$yValue=(HEIGHT/2)+$yValue;
$NumBottom++;
} else {
$yValue=(HEIGHT/2)-$yValue;
$NumTop++;
}
$yValue = ceil($yValue);
// $yValue is now a proper y coordinate
// Now time to do some spacing out
if($yValue < 10){
$yValue+=(10+abs($yValue))+rand(10,20);
}
if($yValue > (HEIGHT - 10)){
$yValue-=((HEIGHT/2)-rand(10,20));
}
$i = 1;
while($Conflict = $this->scan_array_range($this->yValues, abs($yValue-13), $yValue+13)) {
if($i > 10){
break;
}
if(!$this->scan_array_range($this->yValues, abs($yValue-5), $yValue-20)){
$yValue -= 20;
}
$yValue=$Conflict + rand(10, 20);
if($yValue>HEIGHT-10){
$yValue-=ceil(HEIGHT/2.5);
} elseif($yValue<10) {
$yValue+=ceil(HEIGHT/2.5);
}
$i++;
}
$Artist->y = $yValue;
$this->yValues[$yValue] = $ArtistID;
}
reset($this->Artists);
reset($this->xValues);
reset($this->yValues);
}
// Calculate the ideal distance from the center point ($Rootx, $Rooty) to the artist's point on the board
// Pythagoras as fun!
function calculate_distance($SimilarityCoefficient, $Rootx, $Rooty){
$MaxWidth = WIDTH - $Rootx;
$MaxHeight = HEIGHT - $Rooty;
$x = $MaxWidth - ($SimilarityCoefficient*$MaxWidth*.01); // Possible x value
$y = $MaxHeight - ($SimilarityCoefficient*$MaxHeight); // Possible y value
$Hypot = hypot($Rootx - $x, $Rooty - $y);
return $MaxWidth - $Hypot;
}
function similarity($Score, $TotalArtistScore){
return (pow(($Score/($TotalArtistScore+1)), (1/1)));
}
function scan_array_range($Array, $Start, $Finish){
if($Start<0){
die($Start);
}
for ($i = $Start; $i<=$Finish; $i++){
if(isset($Array[$i])){
return $i;
}
}
return false;
}
function write_artists(){
?>
<div style="position:absolute;bottom:<?=$this->y-10?>px;left:<?=$this->x - $this->NameLength*4?>px;font-size:13pt;white-space:nowrap;" class="similar_artist_header">
<?=$this->Name?>
</div>
<?
foreach($this->Artists as $Artist){
if($Artist->ID == $this->ID){
continue;
}
$xPosition = $Artist->x - $Artist->NameLength*4;
if($xPosition<0){
$xPosition=3;
$Artist->x = $xPosition;
}
$Decimal = $this->Similar[$Artist->ID]['Decimal'];
if($Decimal<0.2){
$FontSize = 8;
} elseif($Decimal<0.3){
$FontSize = 9;
} elseif($Decimal<0.4){
$FontSize = 10;
} else {
$FontSize = 12;
}
?>
<div style="position:absolute;top:<?=$Artist->y-5?>px;left:<?=$xPosition?>px;font-size:<?=$FontSize?>pt;white-space:nowrap;">
<a href="artist.php?id=<?=$Artist->ID?>" class="similar_artist"><?=$Artist->Name?></a>
</div>
<?
}
reset($this->Artists);
}
function background_image(){
global $Img;
reset($this->Similar);
foreach($this->Similar as $SimilarArtist) {
list($ArtistID, $Val) = array_values($SimilarArtist);
$Artist = $this->Artists[$ArtistID];
$Decimal = $this->Similar[$ArtistID]['Decimal'];
$Width = ceil($Decimal*4)+1;
$Img->line($this->x, $this->y, $Artist->x, $Artist->y,$Img->color(199,218,255), $Width);
unset($Artist->Similar[$this->ID]);
reset($Artist->Similar);
foreach($Artist->Similar as $SimilarArtist2) {
list($Artist2ID) = array_values($SimilarArtist2);
if($this->Artists[$Artist2ID]){
$Artist2 = $this->Artists[$Artist2ID];
$Img->line($Artist->x, $Artist->y, $Artist2->x, $Artist2->y,$Img->color(173,201,255));
unset($Artist2->Similar[$ArtistID]);
}
}
reset($this->xValues);
}
$Img->make_png(SERVER_ROOT.'/static/similar/'.$this->ID.'.png');
}
function dump(){
echo "Similarities:\n";
foreach($this->Artists as $Artist){
echo $Artist->ID;
echo ' - ';
echo $Artist->Name;
echo "\n";
echo "x - ".$Artist->x."\n";
echo "y - ".$Artist->y."\n";
print_r($this->Similar[$Artist->ID]);
//print_r($Artist->Similar);
echo "\n\n---\n\n";
}
}
}
?>

317
classes/class_cache.php Normal file
View File

@ -0,0 +1,317 @@
<?
/*************************************************************************|
|--------------- Caching class -------------------------------------------|
|*************************************************************************|
This class is a wrapper for the Memcache class, and it's been written in
order to better handle the caching of full pages with bits of dynamic
content that are different for every user.
As this inherits memcache, all of the default memcache methods work -
however, this class has page caching functions superior to those of
memcache.
Also, Memcache::get and Memcache::set have been wrapped by
CACHE::get_value and CACHE::cache_value. get_value uses the same argument
as get, but cache_value only takes the key, the value, and the duration
(no zlib).
//unix sockets
memcached -d -m 5120 -s /var/run/memcached.sock -a 0777 -t16 -C -u root
//tcp bind
memcached -d -m 8192 -l 10.10.0.1 -t8 -C
|*************************************************************************/
if (!extension_loaded('memcache')) {
error('Memcache Extension not loaded.');
}
class CACHE extends Memcache {
public $CacheHits = array();
public $MemcacheDBArray = array();
public $MemcacheDBKey = '';
protected $InTransaction = false;
public $Time = 0;
public $CanClear = false;
function __construct() {
$this->pconnect(MEMCACHED_HOST, MEMCACHED_PORT);
//$this->connect('localhost', 11211);
}
//---------- Caching functions ----------//
// Allows us to set an expiration on otherwise perminantly cache'd values
// Useful for disabled users, locked threads, basically reducing ram usage
public function expire_value($Key, $Duration=2592000) {
$StartTime=microtime(true);
$this->set($Key, $this->get($Key), $Duration);
$this->Time+=(microtime(true)-$StartTime)*1000;
}
// Wrapper for Memcache::set, with the zlib option removed and default duration of 30 days
public function cache_value($Key, $Value, $Duration=2592000) {
$StartTime=microtime(true);
if (empty($Key)) {
trigger_error("Cache insert failed for empty key");
}
if (!$this->set($Key, $Value, 0, $Duration)) {
trigger_error("Cache insert failed for key $Key");
}
$this->Time+=(microtime(true)-$StartTime)*1000;
}
public function replace_value($Key, $Value, $Duration=2592000) {
$StartTime=microtime(true);
$this->replace($Key, $Value, false, $Duration);
$this->Time+=(microtime(true)-$StartTime)*1000;
}
public function get_value($Key, $NoCache=false) {
$StartTime=microtime(true);
if (empty($Key)) {
trigger_error("Cache retrieval failed for empty key");
}
if (isset($_GET['clearcache']) && $this->CanClear) {
if ($_GET['clearcache'] == 1) {
//Because check_perms isn't true until loggeduser is pulled from the cache, we have to remove the entries loaded before the loggeduser data
//Because of this, not user cache data will require a secondary pageload following the clearcache to update
if (count($this->CacheHits) > 0) {
foreach ($this->CacheHits as $Key => $Entry) {
$this->delete($Key);
unset($this->CacheHits[$Key]);
}
}
$this->delete($Key);
$this->Time+=(microtime(true)-$StartTime)*1000;
return false;
} elseif ($_GET['clearcache'] == $Key) {
$this->delete($Key);
$this->Time+=(microtime(true)-$StartTime)*1000;
return false;
} elseif (in_array($_GET['clearcache'], $this->CacheHits)) {
unset($this->CacheHits[$_GET['clearcache']]);
$this->delete($_GET['clearcache']);
}
}
//For cases like the forums, if a keys already loaded grab the existing pointer
if (isset($this->CacheHits[$Key]) && !$NoCache) {
$this->Time+=(microtime(true)-$StartTime)*1000;
return $this->CacheHits[$Key];
}
$Return = $this->get($Key);
if ($Return && !$NoCache) {
$this->CacheHits[$Key] = $Return;
}
$this->Time+=(microtime(true)-$StartTime)*1000;
return $Return;
}
// Wrapper for Memcache::delete. For a reason, see above.
public function delete_value($Key) {
$StartTime=microtime(true);
if (empty($Key)) {
trigger_error("Cache deletion failed for empty key");
}
if (!$this->delete($Key)) {
//trigger_error("Cache delete failed for key $Key");
}
$this->Time+=(microtime(true)-$StartTime)*1000;
}
//---------- memcachedb functions ----------//
public function begin_transaction($Key) {
$Value = $this->get($Key);
if (!is_array($Value)) {
$this->InTransaction = false;
$this->MemcacheDBKey = array();
$this->MemcacheDBKey = '';
return false;
}
$this->MemcacheDBArray = $Value;
$this->MemcacheDBKey = $Key;
$this->InTransaction = true;
return true;
}
public function cancel_transaction() {
$this->InTransaction = false;
$this->MemcacheDBKey = array();
$this->MemcacheDBKey = '';
}
public function commit_transaction($Time=2592000) {
if (!$this->InTransaction) {
return false;
}
$this->cache_value($this->MemcacheDBKey, $this->MemcacheDBArray, $Time);
$this->InTransaction = false;
}
// Updates multiple rows in an array
public function update_transaction($Rows, $Values) {
if (!$this->InTransaction) {
return false;
}
$Array = $this->MemcacheDBArray;
if (is_array($Rows)) {
$i = 0;
$Keys = $Rows[0];
$Property = $Rows[1];
foreach ($Keys as $Row) {
$Array[$Row][$Property] = $Values[$i];
$i++;
}
} else {
$Array[$Rows] = $Values;
}
$this->MemcacheDBArray = $Array;
}
// Updates multiple values in a single row in an array
// $Values must be an associative array with key:value pairs like in the array we're updating
public function update_row($Row, $Values) {
if (!$this->InTransaction) {
return false;
}
if ($Row === false) {
$UpdateArray = $this->MemcacheDBArray;
} else {
$UpdateArray = $this->MemcacheDBArray[$Row];
}
foreach ($Values as $Key => $Value) {
if (!array_key_exists($Key, $UpdateArray)) {
trigger_error('Bad transaction key ('.$Key.') for cache '.$this->MemcacheDBKey);
}
if ($Value === '+1') {
if (!is_number($UpdateArray[$Key])) {
trigger_error('Tried to increment non-number ('.$Key.') for cache '.$this->MemcacheDBKey);
}
++$UpdateArray[$Key]; // Increment value
} elseif ($Value === '-1') {
if (!is_number($UpdateArray[$Key])) {
trigger_error('Tried to decrement non-number ('.$Key.') for cache '.$this->MemcacheDBKey);
}
--$UpdateArray[$Key]; // Decrement value
} else {
$UpdateArray[$Key] = $Value; // Otherwise, just alter value
}
}
if ($Row === false) {
$this->MemcacheDBArray = $UpdateArray;
} else {
$this->MemcacheDBArray[$Row] = $UpdateArray;
}
}
// Increments multiple values in a single row in an array
// $Values must be an associative array with key:value pairs like in the array we're updating
public function increment_row($Row, $Values) {
if (!$this->InTransaction) {
return false;
}
if ($Row === false) {
$UpdateArray = $this->MemcacheDBArray;
} else {
$UpdateArray = $this->MemcacheDBArray[$Row];
}
foreach ($Values as $Key => $Value) {
if (!array_key_exists($Key, $UpdateArray)) {
trigger_error('Bad transaction key ('.$Key.') for cache '.$this->MemcacheDBKey);
}
if (!is_number($Value)) {
trigger_error('Tried to increment with non-number ('.$Key.') for cache '.$this->MemcacheDBKey);
}
$UpdateArray[$Key] += $Value; // Increment value
}
if ($Row === false) {
$this->MemcacheDBArray = $UpdateArray;
} else {
$this->MemcacheDBArray[$Row] = $UpdateArray;
}
}
// Insert a value at the beginning of the array
public function insert_front($Key, $Value) {
if (!$this->InTransaction) {
return false;
}
if ($Key === '') {
array_unshift($this->MemcacheDBArray, $Value);
} else {
$this->MemcacheDBArray = array($Key=>$Value) + $this->MemcacheDBArray;
}
}
// Insert a value at the end of the array
public function insert_back($Key, $Value) {
if (!$this->InTransaction) {
return false;
}
if ($Key === '') {
array_push($this->MemcacheDBArray, $Value);
} else {
$this->MemcacheDBArray = $this->MemcacheDBArray + array($Key=>$Value);
}
}
public function insert($Key, $Value) {
if (!$this->InTransaction) {
return false;
}
if ($Key === '') {
$this->MemcacheDBArray[] = $Value;
} else {
$this->MemcacheDBArray[$Key] = $Value;
}
}
public function delete_row($Row) {
if (!$this->InTransaction) {
return false;
}
if (!isset($this->MemcacheDBArray[$Row])) {
trigger_error('Tried to delete non-existent row ('.$Row.') for cache '.$this->MemcacheDBKey);
}
unset($this->MemcacheDBArray[$Row]);
}
public function update($Key, $Rows, $Values, $Time=2592000) {
if (!$this->InTransaction) {
$this->begin_transaction($Key);
$this->update_transaction($Rows, $Values);
$this->commit_transaction($Time);
} else {
$this->update_transaction($Rows, $Values);
}
}
// Built-in increment/decrement functions are said not to be thread safe
public function increment($Key, $Value=1) {
if(($OldValue = $this->get($Key)) === false || !is_number($Value)) {
return false;
}
$this->replace_value($Key, $OldValue+$Value);
}
public function decrement($Key, $Value=1) {
if(($OldValue = $this->get($Key)) === false || !is_number($Value) || !is_number($OldValue)) {
return false;
}
if($Value > $OldValue) {
$OldValue = $Value = 0;
}
$this->replace_value($Key, $OldValue-$Value);
}
}

193
classes/class_charts.php Normal file
View File

@ -0,0 +1,193 @@
<?
class GOOGLE_CHARTS {
protected $URL = 'http://chart.apis.google.com/chart';
protected $Labels = array();
protected $Data = array();
protected $Options = array();
public function __construct($Type, $Width, $Height, $Options) {
if ($Width * $Height > 300000 || $Height > 1000 || $Width > 1000) {
trigger_error('Tried to make chart too large.');
}
$this->URL .= '?cht='.$Type.'&amp;chs='.$Width.'x'.$Height;
$this->Options = $Options;
}
protected function encode($Number) {
if ($Number == -1) {
return '__';
}
$CharKey = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';
return $CharKey[floor($Number/64)].$CharKey[floor($Number%64)];
}
public function color($Colors) {
$this->URL .= '&amp;chco='.$Colors;
}
public function lines($Thickness, $Solid=1, $Blank=0) {
$this->URL .= '&amp;chls='.$Thickness.','.$Solid.','.$Blank;
}
public function title($Title, $Color='', $Size='') {
$this->URL .= '&amp;chtt='.str_replace(array(' ',"\n"), array('+','|'), $Title);
if (!empty($Color)) {
$this->URL .= '&amp;chts='.$Color;
}
if (!empty($Size)) {
$this->URL .= ','.$Size;
}
}
public function legend($Items, $Placement='') {
$this->URL .= '&amp;chdl='.str_replace(' ', '+', implode('|', $Items));
if (!empty($Placement)) {
if (!in_array($Placement, array('b','t','r','l','bv','tv'))) {
trigger_error('Invalid legend placement.');
}
$this->URL .= '&amp;chdlp='.$Placement;
}
}
public function add($Label, $Data) {
if ($Label !== false) {
$this->Labels[] = $Label;
}
$this->Data[] = $Data;
}
public function grid_lines($SpacingX=0, $SpacingY=-1, $Solid=1, $Blank=1) {
//Can take 2 more parameters for offset, but we're not bothering with that right now
$this->URL .= '&amp;chg='.$SpacingX.','.$SpacingY.','.$Solid.','.$Blank.'';
}
public function transparent() {
$this->URL .= '&amp;chf=bg,s,FFFFFF00';
}
public function url() {
return $this->URL;
}
}
class AREA_GRAPH extends GOOGLE_CHARTS {
public function __construct ($Width, $Height, $Options=array()) {
parent::__construct('lc', $Width, $Height, $Options);
}
public function color ($Color) {
$this->URL .= '&amp;chco='.$Color.'&amp;chm=B,'.$Color.'50,0,0,0';
}
public function generate() {
$Max = max($this->Data);
$Min = (isset($this->Options['Break']))?$Min=min($this->Data):0;
$Data = array();
foreach ($this->Data as $Value) {
$Data[] = $this->encode((($Value-$Min)/($Max-$Min))*4095);
}
$this->URL .= "&amp;chxt=y,x&amp;chxs=0,h&amp;chxl=1:|".implode('|', $this->Labels).'&amp;chxr=0,'.$Min.','.($Max-$Min).'&amp;chd=e:'.implode('', $Data);
}
}
class PIE_CHART extends GOOGLE_CHARTS {
public function __construct ($Width, $Height, $Options=array()) {
$Type = (isset($this->Options['3D']))?'p3':'p';
parent::__construct($Type, $Width, $Height, $Options);
}
public function generate() {
$Sum = array_sum($this->Data);
$Other = isset($this->Options['Other']);
$Sort = isset($this->Options['Sort']);
$LabelPercent = isset($this->Options['Percentage']);
if ($Sort && !empty($this->Labels)) {
array_multisort($this->Data, SORT_DESC, $this->Labels);
} elseif ($Sort) {
sort($this->Data);
$this->Data = array_reverse($this->Data);
}
$Data = array();
$Labels = $this->Labels;
$OtherPercentage = 0.00;
$OtherData = 0;
foreach ($this->Data as $Key => $Value) {
$ThisPercentage = number_format(($Value/$Sum)*100, 2);
$ThisData = ($Value/$Sum)*4095;
if ($Other && $ThisPercentage < 1) {
$OtherPercentage += $ThisPercentage;
$OtherData += $ThisData;
unset($Data[$Key]);
unset($Labels[$Key]);
continue;
}
if ($LabelPercent) {
$Labels[$Key] .= ' ('.$ThisPercentage.'%)';
}
$Data[] = $this->encode($ThisData);
}
if ($OtherPercentage > 0) {
$OtherLabel = 'Other';
if ($LabelPercent) {
$OtherLabel .= ' ('.$OtherPercentage.'%)';
}
$Labels[] = $OtherLabel;
$Data[] = $this->encode($OtherData);
}
$this->URL .= "&amp;chl=".implode('|', $Labels).'&amp;chd=e:'.implode('', $Data);
}
}
class LOG_BAR_GRAPH extends GOOGLE_CHARTS {
//TODO: Finish.
public function __construct ($Base, $Width, $Height, $Options=array()) {
parent::__construct('lc', $Width, $Height, $Options);
}
public function color ($Color) {
$this->URL .= '&amp;chco='.$Color.'&amp;chm=B,'.$Color.'50,0,0,0';
}
public function generate() {
$Max = max($this->Data);
$Min = (isset($this->Options['Break']))?$Min=min($this->Data):0;
$Data = array();
foreach ($this->Data as $Value) {
$Data[] = $this->encode((($Value-$Min)/($Max-$Min))*4095);
}
$this->URL .= "&amp;chxt=y,x&amp;chxs=0,h&amp;chxl=1:|".implode('|', $this->Labels).'&amp;chxr=0,'.$Min.','.($Max-$Min).'&amp;chd=e:'.implode('', $Data);
}
}
class POLL_GRAPH extends GOOGLE_CHARTS {
public function __construct () {
$this->URL .= '?cht=bhg';
}
public function add($Label, $Data) {
if ($Label !== false) {
$this->Labels[] = cut_string($Label,35);
}
$this->Data[] = $Data;
}
public function generate() {
$Count = count($this->Data);
$Height = (30*$Count)+20;
$Max = max($this->Data);
$Sum = array_sum($this->Data);
$Increment = ($Max/$Sum)*25; // * 100% / 4divisions
$Data = array();
$Labels = array();
foreach ($this->Data as $Key => $Value) {
$Data[] = $this->encode(($Value/$Max)*4095);
$Labels[] = '@t'.str_replace(array(' ',','),array('+','\,'),$this->Labels[$Key]).',000000,1,'.round((($Key + 1)/$Count) - (12/$Height),2).':0,12';
}
$this->URL .= "&amp;chbh=25,0,5&amp;chs=214x$Height&amp;chl=0%|".round($Increment,1)."%|".round($Increment * 2,1)."%|".round($Increment * 3,1)."%|".round($Increment * 4,1)."%&amp;chm=".implode('|', $Labels).'&amp;chd=e:'.implode('', $Data);
}
}

48
classes/class_cookie.php Normal file
View File

@ -0,0 +1,48 @@
<?
/*************************************************************************|
|--------------- Cookie class --------------------------------------------|
|*************************************************************************|
This class handles cookies.
$Cookie->get(); is user provided and untrustworthy
|*************************************************************************/
/*
interface COOKIE_INTERFACE {
public function get($Key);
public function set($Key,$Value,$Seconds,$LimitAccess);
public function del($Key);
public function flush();
}
*/
class COOKIE /*implements COOKIE_INTERFACE*/ {
const LIMIT_ACCESS = true; //If true, blocks JS cookie API access by default (can be overridden case by case)
const PREFIX = ''; //In some cases you may desire to prefix your cookies
public function get($Key) {
if (!isset($_COOKIE[SELF::PREFIX.$Key])) {
return false;
}
return $_COOKIE[SELF::PREFIX.$Key];
}
//Pass the 4th optional param as false to allow JS access to the cookie
public function set($Key,$Value,$Seconds = 86400,$LimitAccess = SELF::LIMIT_ACCESS) {
setcookie(SELF::PREFIX.$Key,$Value,time()+$Seconds,'/',SITE_URL,$_SERVER['SERVER_PORT'] === '443',$LimitAccess,false);
}
public function del($Key) {
setcookie(SELF::PREFIX.$Key,'',time()-24*3600); //3600 vs 1 second to account for potential clock desyncs
}
public function flush() {
$Cookies = array_keys($_COOKIE);
foreach ($Cookies as $Cookie) {
$this->del($Cookie);
}
}
}

490
classes/class_debug.php Normal file
View File

@ -0,0 +1,490 @@
<?
// Debug info for developers
define('MAX_TIME', 20000); //Maximum execution time in ms
define('MAX_ERRORS', 0); //Maxmimum errors, warnings, notices we will allow in a page
define('MAX_MEMORY', 80*1024*1024); //Maximum memory used per pageload
define('MAX_QUERIES', 30); //Maxmimum queries
class DEBUG {
public $Errors = array();
public $Flags = array();
public function profile($Automatic='') {
global $ScriptStartTime;
$Reason = array();
if (!empty($Automatic)) {
$Reason[] = $Automatic;
}
$Micro = (microtime(true)-$ScriptStartTime)*1000;
if ($Micro > MAX_TIME && !defined('TIME_EXCEPTION')) {
$Reason[] = number_format($Micro, 3).' ms';
}
$Errors = count($this->get_errors());
if ($Errors > MAX_ERRORS && !defined('ERROR_EXCEPTION')) {
$Reason[] = $Errors.' PHP Errors';
}
/*
$Queries = count($this->get_queries());
if ($Queries > MAX_QUERIES && !defined('QUERY_EXCEPTION')) {
$Reason[] = $Queries.' Queries';
}
*/
$Ram = memory_get_usage(true);
if ($Ram > MAX_MEMORY && !defined('MEMORY_EXCEPTION')) {
$Reason[] = get_size($Ram).' Ram Used';
}
if (isset($_REQUEST['profile'])) {
global $LoggedUser;
$Reason[] = 'Requested by '.$LoggedUser['Username'];
}
if (isset($Reason[0])) {
$this->analysis(implode(', ', $Reason));
return true;
}
return false;
}
public function analysis($Message, $Report='', $Time=43200) {
global $Cache, $Document;
if (empty($Report)) {
$Report = $Message;
}
$Identifier = make_secret(5);
$Cache->cache_value(
'analysis_'.$Identifier,
array(
'url' => $_SERVER['REQUEST_URI'],
'message' => $Report,
'errors' => $this->get_errors(true),
'queries' => $this->get_queries(),
'flags' => $this->get_flags(),
'includes' => $this->get_includes(),
'cache' => $this->get_cache_keys()
),
$Time
);
send_irc('PRIVMSG '.LAB_CHAN.' :'.$Message.' '.$Document.' '.' http://'.NONSSL_SITE_URL.'/tools.php?action=analysis&case='.$Identifier.' http://'.NONSSL_SITE_URL.$_SERVER['REQUEST_URI']);
}
public function set_flag($Event) {
global $ScriptStartTime;
$this->Flags[] = array($Event,(microtime(true)-$ScriptStartTime)*1000,memory_get_usage(true));
}
//This isn't in the constructor because $this is not available, and the function cannot be made static
public function handle_errors() {
//error_reporting(E_ALL ^ E_STRICT | E_WARNING | E_DEPRECATED | E_ERROR | E_PARSE); //E_STRICT disabled
error_reporting(E_WARNING | E_ERROR | E_PARSE);
set_error_handler(array($this, 'php_error_handler'));
}
protected function format_args($Array) {
$LastKey = -1;
$Return = array();
foreach ($Array as $Key => $Val) {
$Return[$Key] = '';
if (!is_int($Key) || $Key != $LastKey+1) {
$Return[$Key] .= "'$Key' => ";
}
if ($Val === true) {
$Return[$Key] .= "true";
} elseif ($Val === false) {
$Return[$Key] .= "false";
} elseif (is_string($Val)) {
$Return[$Key] .= "'$Val'";
} elseif (is_int($Val)) {
$Return[$Key] .= $Val;
} elseif (is_object($Val)) {
$Return[$Key] .= get_class($Val);
} elseif (is_array($Val)) {
$Return[$Key] .= 'array('.$this->format_args($Val).')';
}
$LastKey = $Key;
}
return implode(', ', $Return);
}
public function php_error_handler($Level, $Error, $File, $Line) {
//Who added this, it's still something to pay attention to...
if (stripos('Undefined index', $Error) !== false) {
//return true;
}
$Steps = 1; //Steps to go up in backtrace, default one
$Call = '';
$Args = '';
$Tracer = debug_backtrace();
//This is in case something in this function goes wrong and we get stuck with an infinite loop
if (isset($Tracer[$Steps]['function'], $Tracer[$Steps]['class']) && $Tracer[$Steps]['function'] == 'php_error_handler' && $Tracer[$Steps]['class'] == 'DEBUG') {
return true;
}
//If this error was thrown, we return the function which threw it
if (isset($Tracer[$Steps]['function']) && $Tracer[$Steps]['function'] == 'trigger_error') {
$Steps++;
$File = $Tracer[$Steps]['file'];
$Line = $Tracer[$Steps]['line'];
}
//At this time ONLY Array strict typing is fully supported.
//Allow us to abuse strict typing (IE: function test(Array))
if (preg_match('/^Argument (\d+) passed to \S+ must be an (array), (array|string|integer|double|object) given, called in (\S+) on line (\d+) and defined$/', $Error, $Matches)) {
$Error = 'Type hinting failed on arg '.$Matches[1]. ', expected '.$Matches[2].' but found '.$Matches[3];
$File = $Matches[4];
$Line = $Matches[5];
}
//Lets not be repetative
if (($Tracer[$Steps]['function'] == 'include' || $Tracer[$Steps]['function'] == 'require' ) && isset($Tracer[$Steps]['args'][0]) && $Tracer[$Steps]['args'][0] == $File) {
unset($Tracer[$Steps]['args']);
}
//Class
if (isset($Tracer[$Steps]['class'])) {
$Call .= $Tracer[$Steps]['class'].'::';
}
//Function & args
if (isset($Tracer[$Steps]['function'])) {
$Call .= $Tracer[$Steps]['function'];
if (isset($Tracer[$Steps]['args'][0])) {
$Args = $this->format_args($Tracer[$Steps]['args']);
}
}
//Shorten the path & we're done
$File = str_replace(SERVER_ROOT, '', $File);
$Error = str_replace(SERVER_ROOT, '', $Error);
/*
//Hiding "session_start(): Server 10.10.0.1 (tcp 11211) failed with: No route to host (113)" errors
if($Call != "session_start") {
$this->Errors[] = array($Error, $File.':'.$Line, $Call, $Args);
}
*/
return true;
}
/* Data wrappers */
public function get_flags() {
return $this->Flags;
}
public function get_errors($Light=false) {
//Because the cache can't take some of these variables
if ($Light) {
foreach ($this->Errors as $Key => $Value) {
$this->Errors[$Key][3] = '';
}
}
return $this->Errors;
}
public function get_constants() {
return get_defined_constants(true);
}
public function get_classes() {
foreach (get_declared_classes() as $Class) {
$Classes[$Class]['Vars'] = get_class_vars($Class);
$Classes[$Class]['Functions'] = get_class_methods($Class);
}
return $Classes;
}
public function get_extensions() {
foreach (get_loaded_extensions() as $Extension) {
$Extensions[$Extension]['Functions'] = get_extension_funcs($Extension);
}
return $Extensions;
}
public function get_includes() {
return get_included_files();
}
public function get_cache() {
global $Cache;
return $Cache->CacheHits;
}
public function get_cache_time() {
global $Cache;
return $Cache->Time;
}
public function get_cache_keys() {
global $Cache;
return array_keys($Cache->CacheHits);
}
public function get_sphinx_queries() {
global $SS;
return $SS->Queries;
}
public function get_sphinx_time() {
global $SS;
return $SS->Time;
}
public function get_queries() {
global $DB;
return $DB->Queries;
}
public function get_query_time() {
global $DB;
return $DB->Time;
}
/* Output Formatting */
public function include_table($Includes=false) {
if (!is_array($Includes)) {
$Includes = $this->get_includes();
}
?>
<table width="100%">
<tr>
<td align="left"><strong><a href="#" onclick="$('#debug_include').toggle();return false;">(View)</a> <?=number_format(count($Includes))?> Includes:</strong></td>
</tr>
</table>
<table id="debug_include" class="hidden" width="100%">
<?
foreach ($Includes as $File) {
?>
<tr valign="top">
<td><?=$File?></td>
</tr>
<?
}
?>
</table>
<?
}
public function class_table($Classes=false) {
if (!is_array($Classes)) {
$Classes = $this->get_classes();
}
?>
<table width="100%">
<tr>
<td align="left"><strong><a href="#" onclick="$('#debug_classes').toggle();return false;">(View)</a> Classes:</strong></td>
</tr>
</table>
<table id="debug_classes" class="hidden" width="100%">
<tr>
<td align="left">
<pre><? print_r($Classes) ?></pre>
</td>
</tr>
</table>
<?
}
public function extension_table() {
?>
<table width="100%">
<tr>
<td align="left"><strong><a href="#" onclick="$('#debug_extensions').toggle();return false;">(View)</a> Extensions:</strong></td>
</tr>
</table>
<table id="debug_extensions" class="hidden" width="100%">
<tr>
<td align="left">
<pre><? print_r($this->get_extensions()) ?></pre>
</td>
</tr>
</table>
<?
}
public function flag_table($Flags=false) {
if (!is_array($Flags)) {
$Flags = $this->get_flags();
}
if (empty($Flags)) {
return;
}
?>
<table width="100%">
<tr>
<td align="left"><strong><a href="#" onclick="$('#debug_flags').toggle();return false;">(View)</a> Flags:</strong></td>
</tr>
</table>
<table id="debug_flags" class="hidden" width="100%">
<?
foreach ($Flags as $Flag) {
list($Event,$MicroTime,$Memory) = $Flag;
?>
<tr valign="top">
<td align="left"><?=$Event?></td>
<td align="left"><?=$MicroTime?> ms</td>
<td align="left"><?=get_size($Memory)?></td>
</tr>
<?
}
?>
</table>
<?
}
public function constant_table($Constants=false) {
if (!is_array($Constants)) {
$Constants = $this->get_constants();
}
?>
<table width="100%">
<tr>
<td align="left"><strong><a href="#" onclick="$('#debug_constants').toggle();return false;">(View)</a> Constants:</strong></td>
</tr>
</table>
<table id="debug_constants" class="hidden" width="100%">
<tr>
<td align="left">
<pre><?=display_str(print_r($Constants, true))?></pre>
</td>
</tr>
</table>
<?
}
public function cache_table($CacheData=false) {
global $Cache;
$Header = 'Cache Keys';
$CacheKeys = $this->get_cache_keys();
if (!is_array($CacheData)) {
$CacheData = $this->get_cache();
$Header .= ' ('.number_format($this->get_cache_time(), 5).' ms)';
}
if (empty($CacheData)) {
return;
}
$Header = ' '.number_format(count($CacheData)).' '.$Header.':';
?>
<table width="100%">
<tr>
<td align="left"><strong><a href="#" onclick="$('#debug_cache').toggle();return false;">(View)</a><?=$Header?></strong></td>
</tr>
</table>
<table id="debug_cache" class="hidden" width="100%">
<? foreach($CacheKeys as $Key) { ?>
<tr>
<td align="left">
<a href="#" onclick="$('#debug_cache_<?=$Key?>').toggle(); return false;"><?=display_str($Key)?></a>
</td>
<td align="left">
<pre id="debug_cache_<?=$Key?>" class="hidden"><?=display_str(print_r($Cache->get_value($Key), true))?></pre>
</td>
</tr>
<? } ?>
</table>
<?
}
public function error_table($Errors=false) {
if (!is_array($Errors)) {
$Errors = $this->get_errors();
}
if (empty($Errors)) {
return;
}
?>
<table width="100%">
<tr>
<td align="left"><strong><a href="#" onclick="$('#debug_error').toggle();return false;">(View)</a> <?=number_format(count($Errors))?> Errors:</strong></td>
</tr>
</table>
<table id="debug_error" class="hidden" width="100%">
<?
foreach ($Errors as $Error) {
list($Error,$Location,$Call,$Args) = $Error;
?>
<tr valign="top">
<td align="left"><?=display_str($Call)?>(<?=display_str($Args)?>)</td>
<td align="left"><?=display_str($Error)?></td>
<td align="left"><?=display_str($Location)?></td>
</tr>
<?
}
?>
</table>
<?
}
public function query_table($Queries=false) {
$Header = 'Queries';
if (!is_array($Queries)) {
$Queries = $this->get_queries();
$Header .= ' ('.number_format($this->get_query_time(), 5).' ms)';
}
if (empty($Queries)) {
return;
}
$Header = ' '.number_format(count($Queries)).' '.$Header.':';
?>
<table width="100%">
<tr>
<td align="left"><strong><a href="#" onclick="$('#debug_database').toggle();return false;">(View)</a><?=$Header?></strong></td>
</tr>
</table>
<table id="debug_database" class="hidden" width="100%">
<?
foreach ($Queries as $Query) {
list($SQL,$Time) = $Query;
?>
<tr valign="top">
<td><?=str_replace("\t", '&nbsp;&nbsp;', nl2br(display_str($SQL)))?></td>
<td class="rowa" style="width:130px;" align="left"><?=number_format($Time, 5)?> ms</td>
</tr>
<?
}
?>
</table>
<?
}
public function sphinx_table($Queries=false) {
$Header = 'Searches';
if (!is_array($Queries)) {
$Queries = $this->get_sphinx_queries();
$Header .= ' ('.number_format($this->get_sphinx_time(), 5).' ms)';
}
if (empty($Queries)) {
return;
}
$Header = ' '.number_format(count($Queries)).' '.$Header.':';
?>
<table width="100%">
<tr>
<td align="left"><strong><a href="#" onclick="$('#debug_sphinx').toggle();return false;">(View)</a><?=$Header?></strong></td>
</tr>
</table>
<table id="debug_sphinx" class="hidden" width="100%">
<?
foreach ($Queries as $Query) {
list($Params,$Time) = $Query;
?>
<tr valign="top">
<td><pre><?=str_replace("\t", ' ', display_str($Params))?></pre></td>
<td class="rowa" style="width:130px;" align="left"><?=number_format($Time, 5)?> ms</td>
</tr>
<?
}
?>
</table>
<?
}
}

34
classes/class_encrypt.php Normal file
View File

@ -0,0 +1,34 @@
<?
/*************************************************************************|
|--------------- Encryption class ----------------------------------------|
|*************************************************************************|
This class handles encryption and decryption, that's all folks.
|*************************************************************************/
if (!extension_loaded('mcrypt')) {
error('Mcrypt Extension not loaded.');
}
class CRYPT {
public function encrypt($Str,$Key=ENCKEY) {
srand();
$Str=str_pad($Str, 32-strlen($Str));
$IVSize=mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$IV=mcrypt_create_iv($IVSize, MCRYPT_RAND);
$CryptStr=mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $Key, $Str, MCRYPT_MODE_CBC, $IV);
return base64_encode($IV.$CryptStr);
}
public function decrypt($CryptStr,$Key=ENCKEY) {
if ($CryptStr!='') {
$IV=substr(base64_decode($CryptStr),0,16);
$CryptStr=substr(base64_decode($CryptStr),16);
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $Key, $CryptStr, MCRYPT_MODE_CBC,$IV));
} else {
return '';
}
}
} // class ENCRYPT()
?>

67
classes/class_feed.php Normal file
View File

@ -0,0 +1,67 @@
<?
class FEED {
function open_feed() {
header("Content-type: application/xml; charset=UTF-8");
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n","<rss version=\"2.0\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n\t<channel>\n";
}
function close_feed() {
echo "\t</channel>\n</rss>";
}
function channel($Title, $Description, $Section='') {
echo "\t\t<title>", $Title, " :: ", SITE_NAME, "</title>\n";
echo "\t\t<link>http://", SITE_URL, "/", $Section, "</link>\n";
echo "\t\t<description>", $Description, "</description>\n";
echo "\t\t<language>en-us</language>\n";
echo "\t\t<lastBuildDate>", date('r'), "</lastBuildDate>\n";
echo "\t\t<docs>http://blogs.law.harvard.edu/tech/rss</docs>\n";
echo "\t\t<generator>Gazelle Feed Class</generator>\n\n";
}
function item($Title, $Description, $Page, $Creator, $Comments='', $Category='', $Date='') { //Escape with CDATA, otherwise the feed breaks.
if ($Date == '') {
$Date = date("r");
} else {
$Date = date("r",strtotime($Date));
}
$Site = NONSSL_SITE_URL;
$Item = "\t\t<item>\n";
$Item .= "\t\t\t<title><![CDATA[$Title]]></title>\n";
$Item .= "\t\t\t<description><![CDATA[$Description]]></description>\n";
$Item .= "\t\t\t<pubDate>$Date</pubDate>\n";
$Item .= "\t\t\t<link>http://$Site/$Page</link>\n";
$Item .= "\t\t\t<guid>http://$Site/$Page</guid>\n";
if ($Comments != '') {
$Item .= "\t\t\t<comments>http://$Site/$Comments</comments>\n";
}
if ($Category != '') {
$Item .= "\t\t\t<category><![CDATA[$Category]]></category>\n";
}
$Item .= "\t\t\t<dc:creator>$Creator</dc:creator>\n\t\t</item>\n";
return $Item;
}
function retrieve($CacheKey,$AuthKey,$PassKey) {
global $Cache;
$Entries = $Cache->get_value($CacheKey);
if(!$Entries){
$Entries = array();
} else {
foreach($Entries as $Item){
echo str_replace(array('[[PASSKEY]]','[[AUTHKEY]]'),array(display_str($PassKey),display_str($AuthKey)),$Item);
}
}
}
function populate($CacheKey,$Item) {
global $Cache;
$Entries = $Cache->get_value($CacheKey,true);
if(!$Entries){
$Entries = array();
} else {
if(count($Entries)>=50) {
array_pop($Entries);
}
}
array_unshift($Entries, $Item);
$Cache->cache_value($CacheKey, $Entries, 0); //inf cache
}
}

58
classes/class_image.php Normal file
View File

@ -0,0 +1,58 @@
<?
if (!extension_loaded('gd')) {
error('GD Extension not loaded.');
}
class IMAGE {
var $Image = false;
var $FontSize = 10;
var $Font = '';
var $TextAngle = 0;
function create($Width, $Height) {
$this->Image = imagecreate($Width, $Height);
$this->Font = SERVER_ROOT.'/classes/fonts/VERDANA.TTF';
if(function_exists('imageantialias')){
imageantialias($this->Image, true);
}
}
function color($Red, $Green, $Blue, $Alpha=0){
return imagecolorallocatealpha($this->Image, $Red, $Green, $Blue, $Alpha);
}
function line($x1, $y1, $x2, $y2, $Color, $Thickness = 1){
if($Thickness == 1){
return imageline($this->Image, $x1, $y1, $x2, $y2, $Color);
}
$t = $Thickness / 2 - 0.5;
if ($x1 == $x2 || $y1 == $y2) {
return imagefilledrectangle($this->Image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
}
$k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
$a = $t / sqrt(1 + pow($k, 2));
$Points = array(
round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a),
);
imagefilledpolygon($this->Image, $Points, 4, $Color);
return imagepolygon($this->Image, $Points, 4, $Color);
}
function ellipse($x, $y, $Width, $Height, $Color){
return imageEllipse($this->Image, $x, $y, $Width, $Height, $Color);
}
function text($x, $y, $Color, $Text){
return imagettftext ($this->Image, $this->FontSize,$this->TextAngle, $x, $y, $Color, $this->Font, $Text);
}
function make_png($FileName = NULL){
return imagepng($this->Image, $FileName);
}
}
?>

View File

@ -0,0 +1,218 @@
<?
/**************************************************************************/
/*-- Invite tree class -----------------------------------------------------
***************************************************************************/
class INVITE_TREE {
var $UserID = 0;
var $Visible = true;
// Set things up
function INVITE_TREE($UserID, $Options = array()){
$this->UserID = $UserID;
if($Options['visible'] === false){
$this->Visible = false;
}
}
function make_tree(){
$UserID = $this->UserID;
global $DB;
?>
<div class="invitetree pad">
<?
$DB->query("SELECT
t1.TreePosition,
t1.TreeID,
t1.TreeLevel,
(SELECT
t2.TreePosition FROM invite_tree AS t2
WHERE TreeID=t1.TreeID AND TreeLevel=t1.TreeLevel AND t2.TreePosition>t1.TreePosition
ORDER BY TreePosition LIMIT 1
) AS MaxPosition
FROM invite_tree AS t1
WHERE t1.UserID=$UserID");
list($TreePosition, $TreeID, $TreeLevel, $MaxPosition) = $DB->next_record();
if(!$MaxPosition){ $MaxPosition = 1000000; } // $MaxPermission is null if the user is the last one in that tree on that level
if(!$TreeID){ return; }
$DB->query("
SELECT
it.UserID,
Username,
Donor,
Warned,
Enabled,
PermissionID,
Uploaded,
Downloaded,
Paranoia,
TreePosition,
TreeLevel
FROM invite_tree AS it
JOIN users_main AS um ON um.ID=it.UserID
JOIN users_info AS ui ON ui.UserID=it.UserID
WHERE TreeID=$TreeID
AND TreePosition>$TreePosition
AND TreePosition<$MaxPosition
AND TreeLevel>$TreeLevel
ORDER BY TreePosition");
$PreviousTreeLevel = $TreeLevel;
// Stats for the summary
$MaxTreeLevel = $TreeLevel; // The deepest level (this changes)
$OriginalTreeLevel = $TreeLevel; // The level of the user we're viewing
$BaseTreeLevel = $TreeLevel + 1; // The level of users invited by our user
$Count = 0;
$Branches = 0;
$DisabledCount = 0;
$DonorCount = 0;
$ParanoidCount = 0;
$TotalUpload = 0;
$TotalDownload = 0;
$TopLevelUpload = 0;
$TopLevelDownload = 0;
$ClassSummary = array();
global $Classes;
foreach ($Classes as $ClassID => $Val) {
$ClassSummary[$ClassID] = 0;
}
// We store this in an output buffer, so we can show the summary at the top without having to loop through twice
ob_start();
while(list($ID, $Username, $Donor, $Warned, $Enabled, $Class, $Uploaded, $Downloaded, $Paranoia, $TreePosition, $TreeLevel) = $DB->next_record()){
// Do stats
$Count++;
if($TreeLevel > $MaxTreeLevel){
$MaxTreeLevel = $TreeLevel;
}
if($TreeLevel == $BaseTreeLevel){
$Branches++;
$TopLevelUpload += $Uploaded;
$TopLevelDownload += $Downloaded;
}
$ClassSummary[$Class]++;
if($Enabled == 2){
$DisabledCount++;
}
if($Donor){
$DonorCount++;
}
// Manage tree depth
if($TreeLevel > $PreviousTreeLevel){
for($i = 0; $i<$TreeLevel-$PreviousTreeLevel; $i++){ echo "<ul class=\"invitetree\">\n"; }
} elseif($TreeLevel < $PreviousTreeLevel){
for($i = 0; $i<$PreviousTreeLevel-$TreeLevel; $i++){ echo "</ul>\n"; }
}
?>
<li>
<strong><?=format_username($ID, $Username, $Donor, $Warned, $Enabled == 2 ? false : true, $Class)?></strong>
<?
if(check_paranoia(array('uploaded', 'downloaded'), $Paranoia, $UserClass)) {
$TotalUpload += $Uploaded;
$TotalDownload += $Downloaded;
?>
&nbsp;Uploaded: <strong><?=get_size($Uploaded)?></strong>
&nbsp;Downloaded: <strong><?=get_size($Downloaded)?></strong>
&nbsp;Ratio: <strong><?=ratio($Uploaded, $Downloaded)?></strong>
<?
} else {
$ParanoidCount++;
?>
&nbsp;Paranoia: <strong><?=number_format($Paranoia) ?></strong>
<?
}
?>
</li>
<? $PreviousTreeLevel = $TreeLevel;
}
$Tree = ob_get_clean();
if($Count){
?> <p style="font-weight: bold;">
This tree has <?=$Count?> entries, <?=$Branches?> branches, and a depth of <?=$MaxTreeLevel - $OriginalTreeLevel?>.
It has
<?
$ClassStrings = array();
foreach ($ClassSummary as $ClassID => $ClassCount) {
if($ClassCount == 0) { continue; }
$LastClass = make_class_string($ClassID);
if($ClassCount>1) {
if($LastClass == "Torrent Celebrity") {
$LastClass = 'Torrent Celebrities';
} else {
$LastClass.='s';
}
}
$LastClass= $ClassCount.' '.$LastClass.' (' . number_format(($ClassCount/$Count)*100) . '%)';
$ClassStrings []= $LastClass;
}
if(count($ClassStrings)>1){
array_pop($ClassStrings);
echo implode(', ', $ClassStrings);
echo ' and '.$LastClass;
} else {
echo $LastClass;
}
echo '. ';
echo $DisabledCount;
echo ($DisabledCount==1)?' user is':' users are';
echo ' disabled (';
if($DisabledCount == 0) { echo '0%)'; }
else { echo number_format(($DisabledCount/$Count)*100) . '%)';}
echo ', and ';
echo $DonorCount;
echo ($DonorCount==1)?' user has':' users have';
echo ' donated (';
if($DonorCount == 0) { echo '0%)'; }
else { echo number_format(($DonorCount/$Count)*100) . '%)';}
echo '. </p>';
echo '<p style="font-weight: bold;">';
echo 'The total amount uploaded by the entire tree was '.get_size($TotalUpload);
echo ', the total amount downloaded was '.get_size($TotalDownload);
echo ', and the total ratio is '.ratio($TotalUpload, $TotalDownload).'. ';
echo '</p>';
echo '<p style="font-weight: bold;">';
echo 'The total amount uploaded by direct invitees (the top level) was '.get_size($TopLevelUpload);
echo ', the total amount downloaded was '.get_size($TopLevelDownload);
echo ', and the total ratio is '.ratio($TopLevelUpload, $TopLevelDownload).'. ';
echo 'These numbers include the stats of paranoid users, and will be factored in to the invitation giving script.</p>';
if($ParanoidCount){
echo '<p style="font-weight: bold;">';
echo $ParanoidCount;
echo ($ParanoidCount==1)?' user (':' users (';
echo number_format(($ParanoidCount/$Count)*100);
echo '%) ';
echo ($ParanoidCount==1)?' is':' are';
echo ' too paranoid to have their stats shown here, and ';
echo ($ParanoidCount==1)?' was':' were';
echo ' not factored into the stats for the total tree.';
echo '</p>';
}
}
?>
<br />
<?=$Tree?>
</div>
<?
}
}
?>

194
classes/class_irc.php Normal file
View File

@ -0,0 +1,194 @@
<?
class IRC_DB extends DB_MYSQL {
function halt($Msg) {
global $Bot;
$Bot->send_to($Bot->get_channel(),'The database is currently unavailable try again later');
}
}
abstract class IRC_BOT {
abstract protected function connect_events();
abstract protected function channel_events();
abstract protected function query_events();
abstract protected function listener_events();
protected $Debug = false;
protected $Socket = false;
protected $Data = false;
protected $Whois = false;
protected $Identified = array();
protected $Channels = array();
protected $Messages = array();
protected $LastChan = false;
protected $ListenSocket =false;
protected $Listened = false;
protected $State = 1; //Drones live
public $Restart = 0; //Die by default
public function __construct() {
//ini_set('memory_limit', '12M');
restore_error_handler(); //Avoid PHP error logging
set_time_limit(0);
}
public function connect() {
//Open a socket to the IRC server
$this->Socket = fsockopen(BOT_SERVER, BOT_PORT);
stream_set_blocking($this->Socket, 0);
//create a socket to listen on
$this->ListenSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//socket_set_option($this->ListenSocket, SOL_TCP, SO_REUSEADDR, 1);
socket_set_option($this->ListenSocket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($this->ListenSocket, SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT);
socket_listen($this->ListenSocket);
socket_set_nonblock($this->ListenSocket);
$this->Debug = $Debug;
fwrite($this->Socket, "NICK ".BOT_NICK."Init\n");
fwrite($this->Socket, "USER ".BOT_NICK." * * :IRC Bot\n");
$this->listen();
}
public function disconnect() {
socket_close($this->ListenSocket);
$this->State = 0; //Drones dead
}
public function get_channel() {
preg_match('/.+ PRIVMSG ([^:]+) :.+/', $this->Data, $Channel);
if(preg_match('/#.+/',$Channel[1])) {
return $Channel[1];
} else {
return false;
}
}
public function get_nick() {
preg_match('/:([^!:]+)!.+@[^\s]+ PRIVMSG [^:]+ :.+/', $this->Data, $Nick);
return $Nick[1];
}
protected function get_message() {
preg_match('/:.+ PRIVMSG [^:]+ :(.+)/', $this->Data, $Msg);
return trim($Msg[1]);
}
protected function get_host() {
preg_match('/:[^!:]+!.+@([^\s]+) PRIVMSG [^:]+ :.+/', $this->Data, $Host);
return trim($Host[1]);
}
protected function get_word($Select=1) {
preg_match('/:.+ PRIVMSG [^:]+ :(.+)/', $this->Data, $Word);
$Word = split(' ',$Word[1]);
return trim($Word[$Select]);
}
protected function get_action() {
preg_match('/:.+ PRIVMSG [^:]+ :!(\S+)/', $this->Data, $Action);
return strtoupper($Action[1]);
}
protected function send_raw($Text) {
fwrite($this->Socket, $Text."\n");
}
public function send_to($Channel, $Text) {
fwrite($this->Socket, "PRIVMSG $Channel :$Text\n");
}
protected function whois($Nick) {
$this->Whois = $Nick;
$this->send_raw("WHOIS $Nick");
}
/*
This function uses blacklisted_ip, which is no longer in RC2.
You can probably find it in old RC1 code kicking aronud if you need it.
protected function ip_check($IP,$Gline=false,$Channel=BOT_REPORT_CHAN) {
global $Cache, $DB;
if(blacklisted_ip($IP)) {
$this->send_to($Channel, 'TOR IP Detected: '.$IP);
if ($Gline) {
$this->send_raw('GLINE *@'.$IP.' 90d :DNSBL Proxy');
}
}
$IPBans = $Cache->get_value('ip_bans');
if(!is_array($IPBans)) {
$DB->query("SELECT FromIP, ToIP FROM ip_bans");
$IPBans = $DB->to_array();
$Cache->cache_value('ip_bans', $IPBans, 0);
}
foreach($IPBans as $IPBan) {
list($FromIP, $ToIP) = $IPBan;
$Long = ip2long($IP);
if($Long >= $FromIP && $Long <= $ToIP) {
$this->send_to($Channel, 'Site IP Ban Detected: '.$IP);
if ($Gline) {
$this->send_raw('GLINE *@'.$IP.' 90d :IP Ban');
}
}
}
}*/
protected function listen() {
global $Cache,$DB;
stream_set_timeout($this->Socket, 10000000000);
while($this->State == 1){
if($this->Data = fgets($this->Socket, 256)) {
//IP checks
//if(preg_match('/:\*\*\* (?:REMOTE)?CONNECT: Client connecting (?:.*) \[(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\] \[(.+)\]/', $this->Data, $IP)) {
// $this->ip_check($IP[1],true);
//}
if($this->Debug === true) {
$this->send_to(BOT_DEBUG_CHAN, $this->Data);
}
if($this->Whois !== false) {
$Exp = explode(' ',$this->Data);
if($Exp[1] == '307') {
$this->Identified[$this->Whois] = 1;
$this->send_to($this->LastChan, "$this->Whois correctly identified as a real person!");
$this->Whois = false;
$this->LastChan = false;
} elseif($Exp[6] == '/WHOIS') {
$this->Whois = false;
}
}
if(preg_match("/:([^!]+)![^\s]* QUIT.* /", $this->Data, $Nick)) {
if(isset($this->Identified[$Nick[1]])) {
unset($this->Identified[$Nick[1]]);
}
}
if(preg_match("/End of message of the day./", $this->Data)) {
$this->connect_events();
}
if(preg_match('/PING :(.+)/', $this->Data, $Ping)) {
$this->send_raw('PONG :'.$Ping[1]);
}
if(preg_match('/.*PRIVMSG #.*/',$this->Data)) {
$this->channel_events();
}
if(preg_match("/.* PRIVMSG ".BOT_NICK." .*/",$this->Data)) {
$this->query_events();
}
}
if($this->Listened = @socket_accept($this->ListenSocket)) {
$this->listener_events();
}
$DB->LinkID = false;
$DB->Queries = array();
usleep(5000);
}
}
}
?>

337
classes/class_mysql.php Normal file
View File

@ -0,0 +1,337 @@
<?
//-----------------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////////////
/*//-- MySQL wrapper class ----------------------------------------------------------
This class provides an interface to mysqli. You should always use this class instead
of the mysql/mysqli functions, because this class provides debugging features and a
bunch of other cool stuff.
Everything returned by this class is automatically escaped for output. This can be
turned off by setting $Escape to false in next_record or to_array.
//--------- Basic usage -------------------------------------------------------------
* Creating the object.
require(SERVER_ROOT.'/classes/class_mysql.php');
$DB=NEW DB_MYSQL;
-----
* Making a query
$DB->query("SELECT * FROM table...");
Is functionally equivalent to using mysqli_query("SELECT * FROM table...")
Stores the result set in $this->QueryID
Returns the result set, so you can save it for later (see set_query_id())
-----
* Getting data from a query
$array = $DB->next_record();
Is functionally equivalent to using mysqli_fetch_array($ResultSet)
You do not need to specify a result set - it uses $this-QueryID
-----
* Escaping a string
db_string($str);
Is a wrapper for $DB->escape_str(), which is a wrapper for
mysqli_real_escape_string(). The db_string() function exists so that you
don't have to keep calling $DB->escape_str().
USE THIS FUNCTION EVERY TIME YOU USE AN UNVALIDATED USER-SUPPLIED VALUE IN
A DATABASE QUERY!
//--------- Advanced usage ---------------------------------------------------------
* The conventional way of retrieving a row from a result set is as follows:
list($All,$Columns,$That,$You,$Select)=$DB->next_record();
-----
* This is how you loop over the result set:
while(list($All,$Columns,$That,$You,$Select)=$DB->next_record()){
echo "Do stuff with ".$All." of the ".$Columns.$That.$You.$Select;
}
-----
* There are also a couple more mysqli functions that have been wrapped. They are:
record_count()
Wrapper to mysqli_num_rows()
affected_rows()
Wrapper to mysqli_affected_rows()
inserted_id()
Wrapper to mysqli_insert_id()
close
Wrapper to mysqli_close()
-----
* And, of course, a few handy custom functions.
to_array($Key = false)
Transforms an entire result set into an array (useful in situations where you
can't order the rows properly in the query).
If $Key is set, the function uses $Key as the index (good for looking up a
field). Otherwise, it uses an iterator.
For an example of this function in action, check out forum.php.
collect($Key)
Loops over the result set, creating an array from one of the fields ($Key).
For an example, see forum.php.
set_query_id($ResultSet)
This class can only hold one result set at a time. Using set_query_id allows
you to set the result set that the class is using to the result set in
$ResultSet. This result set should have been obtained earlier by using
$DB-query().
Example:
$FoodRS = $DB->query("SELECT * FROM food");
$DB->query("SELECT * FROM drink");
$Drinks = $DB->next_record();
$DB->set_query_id($FoodRS);
$Food = $DB->next_record();
Of course, this example is contrived, but you get the point.
-------------------------------------------------------------------------------------
*///---------------------------------------------------------------------------------
if (!extension_loaded('mysqli')) {
error('Mysqli Extension not loaded.');
}
//Handles escaping
function db_string($String,$DisableWildcards=false) {
global $DB;
//Remove user input wildcards
if ($DisableWildcards) {
$String = str_replace(array('%','_'), '', $String);
}
//Escape and return
return $DB->escape_str($String);
}
function db_array($Array, $DontEscape = array(), $Quote = false) {
foreach ($Array as $Key => $Val) {
if(!in_array($Key, $DontEscape)) {
if($Quote) {
$Array[$Key] = '\''.db_string(trim($Val)).'\'';
} else {
$Array[$Key] = db_string(trim($Val));
}
}
}
return $Array;
}
//TODO: revisit access levels once Drone is replaced by ZeRobot
class DB_MYSQL {
public $LinkID = false;
protected $QueryID = false;
protected $Record = array();
protected $Row;
protected $Errno = 0;
protected $Error = '';
public $Queries = array();
public $Time = 0.0;
protected $Database = '';
protected $Server = '';
protected $User = '';
protected $Pass = '';
protected $Port = 0;
protected $Socket = '';
function __construct($Database = SQLDB, $User = SQLLOGIN, $Pass = SQLPASS, $Server = SQLHOST, $Port = SQLPORT, $Socket = SQLSOCK) {
$this->Database = $Database;
$this->Server = $Server;
$this->User = $User;
$this->Pass = $Pass;
$this->Port = $Port;
$this->Socket = $Socket;
}
function halt($Msg) {
global $LoggedUser, $Cache, $Debug, $argv;
$DBError='MySQL: '.strval($Msg).' SQL error: '.strval($this->Errno).' ('.strval($this->Error).')';
if ($this->Errno == 1194) { send_irc('PRIVMSG '.ADMIN_CHAN.' :'.$this->Error); }
/*if ($this->Errno == 1194) {
preg_match("Table '(\S+)' is marked as crashed and should be repaired", $this->Error, $Matches);
} */
$Debug->analysis('!dev DB Error',$DBError,3600*24);
if (DEBUG_MODE || check_perms('site_debug') || isset($argv[1])) {
echo '<pre>'.display_str($DBError).'</pre>';
if(DEBUG_MODE || check_perms('site_debug')) {
print_r($this->Queries);
}
die();
} else {
error('-1');
}
}
function connect() {
if(!$this->LinkID) {
$this->LinkID = mysqli_connect($this->Server, $this->User, $this->Pass, $this->Database, $this->Port, $this->Socket); // defined in config.php
if (!$this->LinkID) {
$this->Errno = mysqli_connect_errno();
$this->Error = mysqli_connect_error();
$this->halt('Connection failed (host:'.$this->Server.':'.$this->Port.')');
}
}
}
function query($Query,$AutoHandle=1) {
global $LoggedUser, $Debug;
$QueryStartTime=microtime(true);
$this->connect();
//In the event of a mysql deadlock, we sleep allowing mysql time to unlock then attempt again for a maximum of 5 tries
for($i=1; $i<6; $i++) {
$this->QueryID = mysqli_query($this->LinkID,$Query);
if(!in_array(mysqli_errno($this->LinkID), array(1213, 1205))) {
break;
}
$Debug->analysis('Non-Fatal Deadlock:',$Query,3600*24);
trigger_error("Database deadlock, attempt $i");
sleep($i*rand(2, 5)); // Wait longer as attempts increase
}
$QueryEndTime=microtime(true);
$this->Queries[]=array(display_str($Query),($QueryEndTime-$QueryStartTime)*1000);
$this->Time+=($QueryEndTime-$QueryStartTime)*1000;
if (!$this->QueryID) {
$this->Errno = mysqli_errno($this->LinkID);
$this->Error = mysqli_error($this->LinkID);
if ($AutoHandle) {
$this->halt('Invalid Query: '.$Query);
} else {
return $this->Errno;
}
}
$QueryType = substr($Query,0, 6);
/*
if ($QueryType == 'DELETE' || $QueryType == 'UPDATE') {
if ($this->affected_rows() > 50) {
$Debug->analysis($this->affected_rows().' rows altered:',$Query,3600*24);
}
}
*/
$this->Row = 0;
if ($AutoHandle) { return $this->QueryID; }
}
function query_unb($Query) {
$this->connect();
mysqli_real_query($this->LinkID,$Query);
}
function inserted_id() {
if($this->LinkID) {
return mysqli_insert_id($this->LinkID);
}
}
function next_record($Type=MYSQLI_BOTH, $Escape = true) { // $Escape can be true, false, or an array of keys to not escape
if($this->LinkID) {
$this->Record = mysqli_fetch_array($this->QueryID,$Type);
$this->Row++;
if (!is_array($this->Record)) {
$this->QueryID = FALSE;
} elseif($Escape !== FALSE){
$this->Record = display_array($this->Record, $Escape);
}
return $this->Record;
}
}
function close() {
if($this->LinkID) {
if(!mysqli_close($this->LinkID)) {
$this->halt('Cannot close connection or connection did not open.');
}
$this->LinkID = FALSE;
}
}
function record_count() {
if ($this->QueryID) {
return mysqli_num_rows($this->QueryID);
}
}
function affected_rows() {
if($this->LinkID) {
return mysqli_affected_rows($this->LinkID);
}
}
function info() {
return mysqli_get_host_info($this->LinkID);
}
// You should use db_string() instead.
function escape_str($Str) {
$this->connect(0);
if (is_array($Str)) {
trigger_error('Attempted to escape array.');
return '';
}
return mysqli_real_escape_string($this->LinkID,$Str);
}
// Creates an array from a result set
// If $Key is set, use the $Key column in the result set as the array key
// Otherwise, use an integer
function to_array($Key = false, $Type = MYSQLI_BOTH, $Escape = true) {
$Return = array();
while($Row = mysqli_fetch_array($this->QueryID,$Type)){
if($Escape!==FALSE) {
$Row = display_array($Row, $Escape);
}
if($Key) {
$Return[$Row[$Key]] = $Row;
} else {
$Return[]=$Row;
}
}
mysqli_data_seek($this->QueryID, 0);
return $Return;
}
// Loops through the result set, collecting the $Key column into an array
function collect($Key, $Escape = true) {
$Return = array();
while($Row = mysqli_fetch_array($this->QueryID)){
$Return[] = $Escape ? display_str($Row[$Key]) : $Row[$Key];
}
mysqli_data_seek($this->QueryID, 0);
return $Return;
}
function set_query_id(&$ResultSet){
$this->QueryID = $ResultSet;
$this->Row = 0;
}
function beginning() {
mysqli_data_seek($this->QueryID, 0);
}
}
?>

View File

@ -0,0 +1,85 @@
<?
// Note: at the time this file is loaded, check_perms is not defined. Don't
// call check_paranoia in /classes/script_start.php without ensuring check_perms has been defined
// The following are used throughout the site:
// uploaded, ratio, downloaded: stats
// lastseen: approximate time the user last used the site
// uploads: the full list of the user's uploads
// uploads+: just how many torrents the user has uploaded
// snatched, seeding, leeching: the list of the user's snatched torrents, seeding torrents, and leeching torrents respectively
// snatched+, seeding+, leeching+: the length of those lists respectively
// uniquegroups, perfectflacs: the list of the user's uploads satisfying a particular criterion
// uniquegroups+, perfectflacs+: the length of those lists
// If "uploads+" is disallowed, so is "uploads". So if "uploads" is in the array, the user is a little paranoid, "uploads+", very paranoid.
// The following are almost only used in /sections/user/user.php:
// requiredratio
// requestsfilled_count: the number of requests the user has filled
// requestsfilled_bounty: the bounty thus earned
// requestsfilled_list: the actual list of requests the user has filled
// requestsvoted_...: similar
// artistsadded: the number of artists the user has added
// torrentcomments: the list of comments the user has added to torrents
// +
// collages: the list of collages the user has created
// +
// collagecontribs: the list of collages the user has contributed to
// +
// invitedcount: the number of users this user has directly invited
/**
* Return whether currently logged in user can see $Property on a user with $Paranoia, $UserClass and (optionally) $UserID
* If $Property is an array of properties, returns whether currently logged in user can see *all* $Property ...
*
* @param $Property The property to check, or an array of properties.
* @param $Paranoia The paranoia level to check against.
* @param $UserClass The user class to check against (Staff can see through paranoia of lower classed staff)
* @param $UserID Optional. The user ID of the person being viewed
* @return Boolean representing whether the current user can see through the paranoia setting
*/
function check_paranoia($Property, $Paranoia, $UserClass, $UserID = false) {
global $LoggedUser, $Classes;
if(check_perms('users_override_paranoia', $UserClass)) {
return true;
}
if(!is_array($Paranoia)) {
$Paranoia = unserialize($Paranoia);
}
if(!is_array($Paranoia)) {
$Paranoia = array();
}
if(is_array($Property)) {
$all = true;
foreach ($Property as $P) { $all = $all && check_paranoia($P, $Paranoia, $UserClass, $UserID); }
return $all;
} else {
if(($UserID !== false) && ($LoggedUser['ID'] == $UserID)) {
return true;
}
$May = !in_array($Property, $Paranoia) && !in_array($Property . '+', $Paranoia);
switch ($Property) {
case 'downloaded':
case 'ratio':
case 'uploaded':
case 'lastseen':
$May = $May || check_perms('users_mod', $UserClass);
break;
case 'snatched': case 'snatched+':
$May = $May || check_perms('site_view_torrent_snatchlist', $UserClass);
break;
case 'uploading': case 'uploading+':
case 'seeding': case 'seeding+':
case 'leeching': case 'leeching+':
$May = $May || check_perms('users_view_seedleech', $UserClass);
break;
case 'invitedcount':
$May = $May || check_perms('users_view_invites', $UserClass);
break;
}
return $May;
}
}

43
classes/class_proxies.php Normal file
View File

@ -0,0 +1,43 @@
<?
//Useful: http://www.robtex.com/cnet/
$AllowedProxies = array(
//Opera Turbo (may include opera owned IPs that aren't used for Turbo, but shouldn't run much risk of exploitation)
'64.255.180.*', //Norway
'64.255.164.*', //Norway
'80.239.242.*', //Poland
'80.239.243.*', //Poland
'91.203.96.*', //Norway
'94.246.126.*', //Norway
'94.246.127.*', //Norway
'195.189.142.*', //Norway
'195.189.143.*', //Norway
);
function proxyCheck($IP) {
global $AllowedProxies;
for ($i=0,$il=count($AllowedProxies);$i<$il;++$i) {
//based on the wildcard principle it should never be shorter
if (strlen($IP) < strlen($AllowedProxies[$i])) {
continue;
}
//since we're matching bit for bit iterating from the start
for ($j=0,$jl=strlen($IP);$j<$jl;++$j) {
//completed iteration and no inequality
if ($j == $jl-1 && $IP[$j] === $AllowedProxies[$i][$j]) {
return true;
}
//wildcard
if ($AllowedProxies[$i][$j] === '*') {
return true;
}
//inequality found
if ($IP[$j] !== $AllowedProxies[$i][$j]) {
break;
}
}
}
return false;
}

167
classes/class_search.php Normal file
View File

@ -0,0 +1,167 @@
<?
//Require base class
if(!extension_loaded('sphinx')) {
require(SERVER_ROOT.'/classes/sphinxapi.php');
}
class SPHINX_SEARCH extends SphinxClient {
private $Index='*';
public $TotalResults = 0;
public $Queries = array();
public $Time = 0.0;
public $Filters = array();
function SPHINX_SEARCH() {
parent::__construct();
$this->SetServer(SPHINX_HOST, SPHINX_PORT);
$this->SetMatchMode(SPH_MATCH_EXTENDED2);
}
/****************************************************************
/--- Search function --------------------------------------------
This function queries sphinx for whatever is in $Query, in
extended2 mode. It then fetches the records for each primary key
from memcached (by joining $CachePrefix and the primary key), and
fetches the fields needed ($ReturnData) from the memcached
result.
Any keys not found in memcached are then queried in MySQL, using
$SQL. They are then cached, and merged with the memcached matches
and returned.
$Query - sphinx query
$CachePrefix - Prefix for memcache key (no underscore)
$CacheLength - How long to store data in the cache, if it's found by MySQL
$ReturnData - Array of keys to the array in memcached to return.
If empty, return all.
$SQL - SQL query to fetch results not found in memcached
- Should take the format of:
SELECT fields FROM table WHERE primary key IN(%ids)
where %ids will be replaced by a list of IDs not found in memcached
$IDColumn - The primary key of the SQL table - must be the
same primary key returned by sphinx!
****************************************************************/
function search($Query='', $CachePrefix='', $CacheLength=0, $ReturnData=array(), $SQL = '', $IDColumn='ID') {
global $Cache, $DB;
$QueryStartTime=microtime(true);
$Result = $this->Query($Query, $this->Index);
$QueryEndTime=microtime(true);
$Filters = array();
foreach($this->Filters as $Name => $Value) {
list($Value) = $Value;
$Filters[] = $Name." - ".$Value;
}
$this->Queries[]=array('Params: '.$Query.' Filters: '.implode(", ", $Filters).' Indicies: '.$this->Index,($QueryEndTime-$QueryStartTime)*1000);
$this->Time+=($QueryEndTime-$QueryStartTime)*1000;
if($Result === false) {
if($this->_connerror && !$Cache->get_value('sphinx_crash_reported')) {
send_irc('PRIVMSG '.ADMIN_CHAN.' :!dev Connection to searchd failed');
$Cache->cache_value('sphinx_crash_reported', 1, 3600);
} else {
send_irc('PRIVMSG '.LAB_CHAN.' :Search for "'.$Query.'" ('.str_replace("\n",'',print_r($this->Filters, true)).') failed: '.$this->GetLastError());
}
}
$this->TotalResults = $Result['total'];
$this->SearchTime = $Result['time'];
if(empty($Result['matches'])) {
return false;
}
$Matches = $Result['matches'];
$MatchIDs = array_keys($Matches);
$NotFound = array();
$Skip = array();
if(!empty($ReturnData)) {
$AllFields = false;
} else {
$AllFields = true;
}
foreach($MatchIDs as $Match) {
$Matches[$Match] = $Matches[$Match]['attrs'];
if(!empty($CachePrefix)) {
$Data = $Cache->get_value($CachePrefix.'_'.$Match);
if($Data == false) {
$NotFound[]=$Match;
continue;
}
} else {
$NotFound[]=$Match;
}
if(!$AllFields) {
// Populate list of fields to unset (faster than picking out the ones we need). Should only be run once, on the first cache key
if(empty($Skip)) {
foreach(array_keys($Data) as $Key) {
if(!in_array($Key, $ReturnData)) {
$Skip[]=$Key;
}
}
if(empty($Skip)) {
$AllFields = true;
}
}
foreach($Skip as $Key) {
unset($Data[$Key]);
}
reset($Skip);
}
if(!empty($Data)) {
$Matches[$Match] = array_merge($Matches[$Match], $Data);
}
}
if($SQL!='') {
if(!empty($NotFound)) {
$DB->query(str_replace('%ids', implode(',',$NotFound), $SQL));
while($Data = $DB->next_record(MYSQLI_ASSOC)) {
$Matches[$Data[$IDColumn]] = array_merge($Matches[$Data[$IDColumn]], $Data);
$Cache->cache_value($CachePrefix.'_'.$Data[$IDColumn], $Data, $CacheLength);
}
}
} else {
$Matches = array('matches'=>$Matches,'notfound'=>$NotFound);
}
return $Matches;
}
function limit($Start, $Length, $MaxMatches=SPHINX_MATCHES_START) {
if(check_perms('site_search_many')) {
$MaxMatches = 500000;
}
$this->SetLimits((int)$Start, (int)$Length, $MaxMatches, 0);
}
function set_index($Index) {
$this->Index = $Index;
}
function set_filter($Name, $Val, $Exclude=false) {
$this->Filters[$Name] = $Val;
$this->SetFilter($Name, $Val, $Exclude);
}
function set_filter_range($Name, $Min, $Max, $Exclude) {
$this->Filters[$Name] = array($Min.'-'.$Max);
$this->SetFilterRange($Name, $Min, $Max, $Exclude);
}
function escape_string($String) {
return strtr($String, array('('=>'\(', ')'=>'\)', '|'=>'\|', '-'=>'\-', '@'=>'\@', '~'=>'\~', '&'=>'\&', '/'=>'\/'));
}
}
?>

View File

@ -0,0 +1,81 @@
<?
// Example :
// $TPL = new TEMPLATE;
// $TPL->open('inv.tpl');
// $TPL->set('ADDRESS1',$TPL->str_align(57,$UADDRESS1,'l',' '));
// $TPL->get();
class TEMPLATE {
var $file='';
var $vars=array();
function open($file) {
$this->file=file($file);
}
function set($name,$var,$ifnone="<i>-None-</i>") {
if ($name!='') {
$this->vars[$name][0]=$var;
$this->vars[$name][1]=$ifnone;
}
}
function show() {
$TMPVAR='';
for($i=0; $i<sizeof($this->file); $i++) {
$TMPVAR=$this->file[$i];
foreach($this->vars as $k=>$v) {
if ($v[1]!="" && $v[0]=="") { $v[0]=$v[1]; }
$TMPVAR=str_replace('{{'.$k.'}}',$v[0],$TMPVAR);
}
print $TMPVAR;
}
}
function get() {
$RESULT='';
$TMPVAR='';
for($i=0; $i<sizeof($this->file); $i++) {
$TMPVAR=$this->file[$i];
foreach($this->vars as $k=>$v) {
if ($v[1]!="" && $v[0]=="") { $v[0]=$v[1]; }
$TMPVAR=str_replace('{{'.$k.'}}',$v[0],$TMPVAR);
}
$RESULT.=$TMPVAR;
}
return $RESULT;
}
function str_align($len,$str,$align,$fill) {
$strlen=strlen($str);
if ($strlen>$len) {
return substr($str, 0, $len);
} elseif (($strlen==0)||($len==0)) {
return '';
} else {
if (($align=='l')||($align=='left')) {
$result=$str.str_repeat($fill,($len-$strlen));
} elseif (($align=='r')||($align=='right')) {
$result=str_repeat($fill,($len-$strlen)).$str;
} elseif (($align=='c')||($align=='center')) {
$snm=intval(($len-$strlen)/2);
if (($strlen+($snm*2))==$len) {
$result=str_repeat($fill,$snm).$str;
} else {
$result=str_repeat($fill,$snm+1).$str;
}
$result.=str_repeat($fill,$snm);
}
return $result;
}
}
}
?>

659
classes/class_text.php Normal file
View File

@ -0,0 +1,659 @@
<?
class TEXT {
// tag=>max number of attributes
private $ValidTags = array('b'=>0, 'u'=>0, 'i'=>0, 's'=>0, '*'=>0, 'artist'=>0, 'user'=>0, 'n'=>0, 'inlineurl'=>0, 'inlinesize'=>1, 'align'=>1, 'color'=>1, 'colour'=>1, 'size'=>1, 'url'=>1, 'img'=>1, 'quote'=>1, 'pre'=>1, 'tex'=>0, 'hide'=>1, 'plain'=>0
);
private $Smileys = array(
':angry:' => 'angry.gif',
':-D' => 'biggrin.gif',
':D' => 'biggrin.gif',
':|' => 'blank.gif',
':-|' => 'blank.gif',
':blush:' => 'blush.gif',
':cool:' => 'cool.gif',
':\'(' => 'crying.gif',
'&gt;.&gt;' => 'eyesright.gif',
':frown:' => 'frown.gif',
'&lt;3' => 'heart.gif',
':unsure:' => 'hmm.gif',
':whatlove:' => 'ilu.gif',
':lol:' => 'laughing.gif',
':loveflac:' => 'loveflac.gif',
':ninja:' => 'ninja.gif',
':no:' => 'no.gif',
':nod:' => 'nod.gif',
':ohno:' => 'ohnoes.gif',
':ohnoes:' => 'ohnoes.gif',
':omg:' => 'omg.gif',
':o' => 'ohshit.gif',
':O' => 'ohshit.gif',
':paddle:' => 'paddle.gif',
':(' => 'sad.gif',
':-(' => 'sad.gif',
':shifty:' => 'shifty.gif',
':sick:' => 'sick.gif',
':)' => 'smile.gif',
':-)' => 'smile.gif',
':sorry:' => 'sorry.gif',
':thanks:' => 'thanks.gif',
':P' => 'tongue.gif',
':-P' => 'tongue.gif',
':-p' => 'tongue.gif',
':wave:' => 'wave.gif',
':wink:' => 'wink.gif',
':creepy:' => 'creepy.gif',
':worried:' => 'worried.gif',
':wtf:' => 'wtf.gif',
':wub:' => 'wub.gif'
);
private $NoImg = 0; // If images should be turned into URLs
private $Levels = 0; // If images should be turned into URLs
function __construct() {
foreach($this->Smileys as $Key=>$Val) {
$this->Smileys[$Key] = '<img border="0" src="'.STATIC_SERVER.'common/smileys/'.$Val.'" alt="" />';
}
reset($this->Smileys);
}
function full_format($Str) {
$Str = display_str($Str);
//Inline links
$Str = preg_replace('/(?<!(\[url\]|\[url\=|\[img\=|\[img\]))http(s)?:\/\//i', '$1[inlineurl]http$2://', $Str);
// For anonym.to links. We can't have this in the regex because php freaks out at the ?, even if it's escaped
$Str = strtr($Str, array('?[inlineurl]http'=>'?http', '=[inlineurl]http'=>'=http'));
$Str = preg_replace('/\=\=\=\=([^=].*)\=\=\=\=/i', '[inlinesize=3]$1[/inlinesize]', $Str);
$Str = preg_replace('/\=\=\=([^=].*)\=\=\=/i', '[inlinesize=5]$1[/inlinesize]', $Str);
$Str = preg_replace('/\=\=([^=].*)\=\=/i', '[inlinesize=7]$1[/inlinesize]', $Str);
$Str = $this->parse($Str);
$HTML = $this->to_html($Str);
$HTML = nl2br($HTML);
return $HTML;
}
function strip_bbcode($Str) {
$Str = display_str($Str);
//Inline links
$Str = preg_replace('/(?<!(\[url\]|\[url\=|\[img\=|\[img\]))http(s)?:\/\//i', '$1[inlineurl]http$2://', $Str);
$Str = $this->parse($Str);
$Str = $this->raw_text($Str);
$Str = nl2br($Str);
return $Str;
}
function valid_url($Str, $Extension = '', $Inline = false) {
$Regex = '/^';
$Regex .= '(https?|ftps?|irc):\/\/'; // protocol
$Regex .= '(\w+(:\w+)?@)?'; // user:pass@
$Regex .= '(';
$Regex .= '(([0-9]{1,3}\.){3}[0-9]{1,3})|'; // IP or...
$Regex .= '(([a-z0-9\-\_]+\.)+\w{2,6})'; // sub.sub.sub.host.com
$Regex .= ')';
$Regex .= '(:[0-9]{1,5})?'; // port
$Regex .= '\/?'; // slash?
$Regex .= '(\/?[0-9a-z\-_.,&=@~%\/:;()+!]+)*'; // /file
if(!empty($Extension)) {
$Regex.=$Extension;
}
// query string
if ($Inline) {
$Regex .= '(\?([0-9a-z\-_.,%\/\@~&=:;()+*\^$!]|\[\d*\])*)?';
} else {
$Regex .= '(\?[0-9a-z\-_.,%\/\@[\]~&=:;()+*\^$!]*)?';
}
$Regex .= '(#[a-z0-9\-_.,%\/\@[\]~&=:;()+*\^$!]*)?'; // #anchor
$Regex .= '$/i';
return preg_match($Regex, $Str, $Matches);
}
function local_url($Str) {
$URLInfo = parse_url($Str);
if(!$URLInfo) { return false; }
$Host = $URLInfo['host'];
if($Host == NONSSL_SITE_URL || $Host == SSL_SITE_URL || $Host == 'www.'.NONSSL_SITE_URL) {
$URL = $URLInfo['path'];
if(!empty($URLInfo['query'])) {
$URL.='?'.$URLInfo['query'];
}
if(!empty($URLInfo['fragment'])) {
$URL.='#'.$URLInfo['fragment'];
}
return $URL;
} else {
return false;
}
}
/* How parsing works
Parsing takes $Str, breaks it into blocks, and builds it into $Array.
Blocks start at the beginning of $Str, when the parser encounters a [, and after a tag has been closed.
This is all done in a loop.
EXPLANATION OF PARSER LOGIC
1) Find the next tag (regex)
1a) If there aren't any tags left, write everything remaining to a block and return (done parsing)
1b) If the next tag isn't where the pointer is, write everything up to there to a text block.
2) See if it's a [[wiki-link]] or an ordinary tag, and get the tag name
3) If it's not a wiki link:
3a) check it against the $this->ValidTags array to see if it's actually a tag and not [bullshit]
If it's [not a tag], just leave it as plaintext and move on
3b) Get the attribute, if it exists [name=attribute]
4) Move the pointer past the end of the tag
5) Find out where the tag closes (beginning of [/tag])
5a) Different for different types of tag. Some tags don't close, others are weird like [*]
5b) If it's a normal tag, it may have versions of itself nested inside - eg:
[quote=bob]*
[quote=joe]I am a redneck!**[/quote]
Me too!
***[/quote]
If we're at the position *, the first [/quote] tag is denoted by **.
However, our quote tag doesn't actually close there. We must perform
a loop which checks the number of opening [quote] tags, and make sure
they are all closed before we find our final [/quote] tag (***).
5c) Get the contents between [open] and [/close] and call it the block.
In many cases, this will be parsed itself later on, in a new parse() call.
5d) Move the pointer past the end of the [/close] tag.
6) Depending on what type of tag we're dealing with, create an array with the attribute and block.
In many cases, the block may be parsed here itself. Stick them in the $Array.
7) Increment array pointer, start again (past the end of the [/close] tag)
*/
function parse($Str) {
$i = 0; // Pointer to keep track of where we are in $Str
$Len = strlen($Str);
$Array = array();
$ArrayPos = 0;
while($i<$Len) {
$Block = '';
// 1) Find the next tag (regex)
// [name(=attribute)?]|[[wiki-link]]
$IsTag = preg_match("/((\[[a-zA-Z*]+)(=(?:[^\n'\"\[\]]|\[\d*\])+)?\])|(\[\[[^\n\"'\[\]]+\]\])/", $Str, $Tag, PREG_OFFSET_CAPTURE, $i);
// 1a) If there aren't any tags left, write everything remaining to a block
if(!$IsTag) {
// No more tags
$Array[$ArrayPos] = substr($Str, $i);
break;
}
// 1b) If the next tag isn't where the pointer is, write everything up to there to a text block.
$TagPos = $Tag[0][1];
if($TagPos>$i) {
$Array[$ArrayPos] = substr($Str, $i, $TagPos-$i);
++$ArrayPos;
$i=$TagPos;
}
// 2) See if it's a [[wiki-link]] or an ordinary tag, and get the tag name
if(!empty($Tag[4][0])) { // Wiki-link
$WikiLink = true;
$TagName = substr($Tag[4][0], 2, -2);
$Attrib = '';
} else { // 3) If it's not a wiki link:
$WikiLink = false;
$TagName = strtolower(substr($Tag[2][0], 1));
//3a) check it against the $this->ValidTags array to see if it's actually a tag and not [bullshit]
if(!isset($this->ValidTags[$TagName])) {
$Array[$ArrayPos] = substr($Str, $i, ($TagPos-$i)+strlen($Tag[0][0]));
$i=$TagPos+strlen($Tag[0][0]);
++$ArrayPos;
continue;
}
$MaxAttribs = $this->ValidTags[$TagName];
// 3b) Get the attribute, if it exists [name=attribute]
if(!empty($Tag[3][0])) {
$Attrib = substr($Tag[3][0], 1);
} else {
$Attrib='';
}
}
// 4) Move the pointer past the end of the tag
$i=$TagPos+strlen($Tag[0][0]);
// 5) Find out where the tag closes (beginning of [/tag])
// Unfortunately, BBCode doesn't have nice standards like xhtml
// [*], [img=...], and http:// follow different formats
// Thus, we have to handle these before we handle the majority of tags
//5a) Different for different types of tag. Some tags don't close, others are weird like [*]
if($TagName == 'img' && !empty($Tag[3][0])) { //[img=...]
$Block = ''; // Nothing inside this tag
// Don't need to touch $i
} elseif($TagName == 'inlineurl') { // We did a big replace early on to turn http:// into [inlineurl]http://
// Let's say the block can stop at a newline or a space
$CloseTag = strcspn($Str, " \n\r", $i);
if($CloseTag === false) { // block finishes with URL
$CloseTag = $Len;
}
if(preg_match('/[!;,.?:]+$/',substr($Str, $i, $CloseTag), $Match)) {
$CloseTag -= strlen($Match[0]);
}
$URL = substr($Str, $i, $CloseTag);
if(substr($URL, -1) == ')' && substr_count($URL, '(') < substr_count($URL, ')')) {
$CloseTag--;
$URL = substr($URL, 0, -1);
}
$Block = $URL; // Get the URL
// strcspn returns the number of characters after the offset $i, not after the beginning of the string
// Therefore, we use += instead of the = everywhere else
$i += $CloseTag; // 5d) Move the pointer past the end of the [/close] tag.
} elseif($WikiLink == true || $TagName == 'n') {
// Don't need to do anything - empty tag with no closing
} elseif($TagName == '*') {
// We're in a list. Find where it ends
$NewLine = $i;
do { // Look for \n[*]
$NewLine = strpos($Str, "\n", $NewLine+1);
} while($NewLine!== false && substr($Str, $NewLine+1, 3) == '[*]');
$CloseTag = $NewLine;
if($CloseTag === false) { // block finishes with list
$CloseTag = $Len;
}
$Block = substr($Str, $i, $CloseTag-$i); // Get the list
$i = $CloseTag; // 5d) Move the pointer past the end of the [/close] tag.
} else {
//5b) If it's a normal tag, it may have versions of itself nested inside
$CloseTag = $i-1;
$InTagPos = $i-1;
$NumInOpens = 0;
$NumInCloses = -1;
$InOpenRegex = '/\[('.$TagName.')';
if($MaxAttribs>0) {
$InOpenRegex.="(=[^\n'\"\[\]]+)?";
}
$InOpenRegex.='\]/i';
// Every time we find an internal open tag of the same type, search for the next close tag
// (as the first close tag won't do - it's been opened again)
do {
$CloseTag = stripos($Str, '[/'.$TagName.']', $CloseTag+1);
if($CloseTag === false) {
$CloseTag = $Len;
break;
} else {
$NumInCloses++; // Majority of cases
}
// Is there another open tag inside this one?
$OpenTag = preg_match($InOpenRegex, $Str, $InTag, PREG_OFFSET_CAPTURE, $InTagPos+1);
if(!$OpenTag || $InTag[0][1]>$CloseTag) {
break;
} else {
$InTagPos = $InTag[0][1];
$NumInOpens++;
}
} while($NumInOpens>$NumInCloses);
// Find the internal block inside the tag
$Block = substr($Str, $i, $CloseTag-$i); // 5c) Get the contents between [open] and [/close] and call it the block.
$i = $CloseTag+strlen($TagName)+3; // 5d) Move the pointer past the end of the [/close] tag.
}
// 6) Depending on what type of tag we're dealing with, create an array with the attribute and block.
switch($TagName) {
case 'inlineurl':
$Array[$ArrayPos] = array('Type'=>'inlineurl', 'Attr'=>$Block, 'Val'=>'');
break;
case 'url':
$Array[$ArrayPos] = array('Type'=>'img', 'Attr'=>$Attrib, 'Val'=>$Block);
if(empty($Attrib)) { // [url]http://...[/url] - always set URL to attribute
$Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Block, 'Val'=>'');
} else {
$Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Attrib, 'Val'=>$this->parse($Block));
}
break;
case 'quote':
$Array[$ArrayPos] = array('Type'=>'quote', 'Attr'=>$this->Parse($Attrib), 'Val'=>$this->parse($Block));
break;
case 'img':
case 'image':
if(empty($Block)) {
$Block = $Attrib;
}
$Array[$ArrayPos] = array('Type'=>'img', 'Val'=>$Block);
break;
case 'aud':
case 'mp3':
case 'audio':
if(empty($Block)) {
$Block = $Attrib;
}
$Array[$ArrayPos] = array('Type'=>'aud', 'Val'=>$Block);
break;
case 'user':
$Array[$ArrayPos] = array('Type'=>'user', 'Val'=>$Block);
break;
case 'artist':
$Array[$ArrayPos] = array('Type'=>'artist', 'Val'=>$Block);
break;
case 'tex':
$Array[$ArrayPos] = array('Type'=>'tex', 'Val'=>$Block);
break;
case 'pre':
case 'plain':
$Block = strtr($Block, array('[inlineurl]'=>''));
$Block = preg_replace('/\[inlinesize\=3\](.*?)\[\/inlinesize\]/i', '====$1====', $Block);
$Block = preg_replace('/\[inlinesize\=5\](.*?)\[\/inlinesize\]/i', '===$1===', $Block);
$Block = preg_replace('/\[inlinesize\=7\](.*?)\[\/inlinesize\]/i', '==$1==', $Block);
$Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>$Block);
break;
case 'hide':
$Array[$ArrayPos] = array('Type'=>'hide', 'Attr'=>$Attrib, 'Val'=>$this->parse($Block));
break;
case '*':
$Array[$ArrayPos] = array('Type'=>'list');
$Array[$ArrayPos]['Val'] = explode('[*]', $Block);
foreach($Array[$ArrayPos]['Val'] as $Key=>$Val) {
$Array[$ArrayPos]['Val'][$Key] = $this->parse(trim($Val));
}
break;
case 'n':
$ArrayPos--;
break; // n serves only to disrupt bbcode (backwards compatibility - use [pre])
default:
if($WikiLink == true) {
$Array[$ArrayPos] = array('Type'=>'wiki','Val'=>$TagName);
} else {
// Basic tags, like [b] or [size=5]
$Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>$this->parse($Block));
if(!empty($Attrib) && $MaxAttribs>0) {
$Array[$ArrayPos]['Attr'] = strtolower($Attrib);
}
}
}
$ArrayPos++; // 7) Increment array pointer, start again (past the end of the [/close] tag)
}
return $Array;
}
function to_html($Array) {
$this->Levels++;
if($this->Levels>10) { return $Block['Val']; } // Hax prevention
$Str = '';
foreach($Array as $Block) {
if(is_string($Block)) {
$Str.=$this->smileys($Block);
continue;
}
switch($Block['Type']) {
case 'b':
$Str.='<strong>'.$this->to_html($Block['Val']).'</strong>';
break;
case 'u':
$Str.='<span style="text-decoration: underline;">'.$this->to_html($Block['Val']).'</span>';
break;
case 'i':
$Str.='<em>'.$this->to_html($Block['Val'])."</em>";
break;
case 's':
$Str.='<span style="text-decoration: line-through">'.$this->to_html($Block['Val']).'</span>';
break;
case 'user':
$Str.='<a href="user.php?action=search&amp;search='.urlencode($Block['Val']).'">'.$Block['Val'].'</a>';
break;
case 'artist':
$Str.='<a href="artist.php?artistname='.urlencode(mb_convert_encoding($Block['Val'],"UTF-8","HTML-ENTITIES")).'">'.$Block['Val'].'</a>';
break;
case 'wiki':
$Str.='<a href="wiki.php?action=article&amp;name='.urlencode($Block['Val']).'">'.$Block['Val'].'</a>';
break;
case 'tex':
$Str.='<img src="'.STATIC_SERVER.'blank.gif" onload="if (this.src.substr(this.src.length-9,this.src.length) == \'blank.gif\') { this.src = \'http://chart.apis.google.com/chart?cht=tx&amp;chf=bg,s,FFFFFF00&amp;chl='.urlencode(mb_convert_encoding($Block['Val'],"UTF-8","HTML-ENTITIES")).'&amp;chco=\' + hexify(getComputedStyle(this.parentNode,null).color); }" />';
break;
case 'plain':
$Str.=$Block['Val'];
break;
case 'pre':
$Str.='<pre>'.$Block['Val'].'</pre>';
break;
case 'list':
$Str .= '<ul>';
foreach($Block['Val'] as $Line) {
$Str.='<li>'.$this->to_html($Line).'</li>';
}
$Str.='</ul>';
break;
case 'align':
$ValidAttribs = array('left', 'center', 'right');
if(!in_array($Block['Attr'], $ValidAttribs)) {
$Str.='[align='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/align]';
} else {
$Str.='<div style="text-align:'.$Block['Attr'].'">'.$this->to_html($Block['Val']).'</div>';
}
break;
case 'color':
case 'colour':
$ValidAttribs = array('aqua', 'black', 'blue', 'fuchsia', 'green', 'grey', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red', 'silver', 'teal', 'white', 'yellow');
if(!in_array($Block['Attr'], $ValidAttribs) && !preg_match('/^#[0-9a-f]{6}$/', $Block['Attr'])) {
$Str.='[color='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/color]';
} else {
$Str.='<span style="color:'.$Block['Attr'].'">'.$this->to_html($Block['Val']).'</span>';
}
break;
case 'inlinesize':
case 'size':
$ValidAttribs = array('1','2','3','4','5','6','7','8','9','10');
if(!in_array($Block['Attr'], $ValidAttribs)) {
$Str.='[size='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/size]';
} else {
$Str.='<span class="size'.$Block['Attr'].'">'.$this->to_html($Block['Val']).'</span>';
}
break;
case 'quote':
$this->NoImg++; // No images inside quote tags
if(!empty($Block['Attr'])) {
$Str.= '<strong>'.$this->to_html($Block['Attr']).'</strong> wrote: ';
}
$Str.='<blockquote>'.$this->to_html($Block['Val']).'</blockquote>';
$this->NoImg--;
break;
case 'hide':
$Str.='<strong>'.(($Block['Attr']) ? $Block['Attr'] : 'Hidden text').'</strong>: <a href="javascript:void(0);" onclick="BBCode.spoiler(this);">Show</a>';
$Str.='<blockquote class="hidden spoiler">'.$this->to_html($Block['Val']).'</blockquote>';
break;
case 'img':
if($this->NoImg>0 && $this->valid_url($Block['Val'])) {
$Str.='<a rel="noreferrer" target="_blank" href="'.$Block['Val'].'">'.$Block['Val'].'</a> (image)';
break;
}
if(!$this->valid_url($Block['Val'], '\.(jpe?g|gif|png|bmp|tiff)')) {
$Str.='[img]'.$Block['Val'].'[/img]';
} else {
if(check_perms('site_proxy_images')) {
$Str.='<img style="max-width: 500px;" onclick="lightbox.init(this,500);" alt="'.$Block['Val'].'" src="http://'.SITE_URL.'/image.php?i='.urlencode($Block['Val']).'" />';
} else {
$Str.='<img style="max-width: 500px;" onclick="lightbox.init(this,500);" alt="'.$Block['Val'].'" src="'.$Block['Val'].'" />';
}
}
break;
case 'aud':
if($this->NoImg>0 && $this->valid_url($Block['Val'])) {
$Str.='<a rel="noreferrer" target="_blank" href="'.$Block['Val'].'">'.$Block['Val'].'</a> (audio)';
break;
}
if(!$this->valid_url($Block['Val'], '\.(mp3|ogg|wav)')) {
$Str.='[aud]'.$Block['Val'].'[/aud]';
} else {
//TODO: Proxy this for staff?
$Str.='<audio controls="controls" src="'.$Block['Val'].'"><a rel="noreferrer" target="_blank" href="'.$Block['Val'].'">'.$Block['Val'].'</a></audio>';
}
break;
case 'url':
// Make sure the URL has a label
if(empty($Block['Val'])) {
$Block['Val'] = $Block['Attr'];
$NoName = true; // If there isn't a Val for this
} else {
$Block['Val'] = $this->to_html($Block['Val']);
$NoName = false;
}
if(!$this->valid_url($Block['Attr'])) {
$Str.='[url='.$Block['Attr'].']'.$Block['Val'].'[/url]';
} else {
$LocalURL = $this->local_url($Block['Attr']);
if($LocalURL) {
if($NoName) { $Block['Val'] = substr($LocalURL,1); }
$Str.='<a href="'.$LocalURL.'">'.$Block['Val'].'</a>';
} else {
$Str.='<a rel="noreferrer" target="_blank" href="'.$Block['Attr'].'">'.$Block['Val'].'</a>';
}
}
break;
case 'inlineurl':
if(!$this->valid_url($Block['Attr'], '', true)) {
$Array = $this->parse($Block['Attr']);
$Block['Attr'] = $Array;
$Str.=$this->to_html($Block['Attr']);
}
else {
$LocalURL = $this->local_url($Block['Attr']);
if($LocalURL) {
$Str.='<a href="'.$LocalURL.'">'.substr($LocalURL,1).'</a>';
} else {
$Str.='<a rel="noreferrer" target="_blank" href="'.$Block['Attr'].'">'.$Block['Attr'].'</a>';
}
}
break;
}
}
$this->Levels--;
return $Str;
}
function raw_text($Array) {
$Str = '';
foreach($Array as $Block) {
if(is_string($Block)) {
$Str.=$Block;
continue;
}
switch($Block['Type']) {
case 'b':
case 'u':
case 'i':
case 's':
case 'color':
case 'size':
case 'quote':
case 'align':
$Str.=$this->raw_text($Block['Val']);
break;
case 'tex': //since this will never strip cleanly, just remove it
break;
case 'artist':
case 'user':
case 'wiki':
case 'pre':
case 'aud':
case 'img':
$Str.=$Block['Val'];
break;
case 'list':
foreach($Block['Val'] as $Line) {
$Str.='*'.$this->raw_text($Line);
}
break;
case 'url':
// Make sure the URL has a label
if(empty($Block['Val'])) {
$Block['Val'] = $Block['Attr'];
} else {
$Block['Val'] = $this->raw_text($Block['Val']);
}
$Str.=$Block['Val'];
break;
case 'inlineurl':
if(!$this->valid_url($Block['Attr'], '', true)) {
$Array = $this->parse($Block['Attr']);
$Block['Attr'] = $Array;
$Str.=$this->raw_text($Block['Attr']);
}
else {
$Str.=$Block['Attr'];
}
break;
}
}
return $Str;
}
function smileys($Str) {
global $LoggedUser;
if(!empty($LoggedUser['DisableSmileys'])) {
return $Str;
}
$Str = strtr($Str, $this->Smileys);
return $Str;
}
}
/*
//Uncomment this part to test the class via command line:
function display_str($Str) {return $Str;}
function check_perms($Perm) {return true;}
$Str = "hello
[pre]http://anonym.to/?http://whatshirts.portmerch.com/
====hi====
===hi===
==hi==[/pre]
====hi====
hi";
$Text = NEW TEXT;
echo $Text->full_format($Str);
echo "\n"
*/
?>

166
classes/class_time.php Normal file
View File

@ -0,0 +1,166 @@
<?
if (!extension_loaded('date')) {
error('Date Extension not loaded.');
}
function time_ago($TimeStamp) {
if(!is_number($TimeStamp)) { // Assume that $TimeStamp is SQL timestamp
if($TimeStamp == '0000-00-00 00:00:00') { return false; }
$TimeStamp = strtotime($TimeStamp);
}
if($TimeStamp == 0) { return false; }
return time()-$TimeStamp;
}
function time_diff($TimeStamp,$Levels=2,$Span=true) {
if(!is_number($TimeStamp)) { // Assume that $TimeStamp is SQL timestamp
if($TimeStamp == '0000-00-00 00:00:00') { return 'Never'; }
$TimeStamp = strtotime($TimeStamp);
}
if($TimeStamp == 0) { return 'Never'; }
$Time = time()-$TimeStamp;
//If the time is negative, then we know that it expires in the future
if($Time < 0) {
$Time = -$Time;
$HideAgo = true;
}
$Years=floor($Time/31556926); // seconds in a year
$Remain = $Time - $Years*31556926;
$Months = floor($Remain/2629744); // seconds in a month
$Remain = $Remain - $Months*2629744;
$Weeks = floor($Remain/604800); // seconds in a week
$Remain = $Remain - $Weeks*604800;
$Days = floor($Remain/86400); // seconds in a day
$Remain = $Remain - $Days*86400;
$Hours=floor($Remain/3600);
$Remain = $Remain - $Hours*3600;
$Minutes=floor($Remain/60);
$Remain = $Remain - $Minutes*60;
$Seconds=$Remain;
$Return = '';
if ($Years>0 && $Levels>0) {
if ($Years>1) {
$Return .= $Years.' years';
} else {
$Return .= $Years.' year';
}
$Levels--;
}
if ($Months>0 && $Levels>0) {
if ($Return!='') {
$Return.=', ';
}
if ($Months>1) {
$Return.=$Months.' months';
} else {
$Return.=$Months.' month';
}
$Levels--;
}
if ($Weeks>0 && $Levels>0) {
if ($Return!="") {
$Return.=', ';
}
if ($Weeks>1) {
$Return.=$Weeks.' weeks';
} else {
$Return.=$Weeks.' week';
}
$Levels--;
}
if ($Days>0 && $Levels>0) {
if ($Return!='') {
$Return.=', ';
}
if ($Days>1) {
$Return.=$Days.' days';
} else {
$Return.=$Days.' day';
}
$Levels--;
}
if ($Hours>0 && $Levels>0) {
if ($Return!='') {
$Return.=', ';
}
if ($Hours>1) {
$Return.=$Hours.' hours';
} else {
$Return.=$Hours.' hour';
}
$Levels--;
}
if ($Minutes>0 && $Levels>0) {
if ($Return!='') {
$Return.=' and ';
}
if ($Minutes>1) {
$Return.=$Minutes.' mins';
} else {
$Return.=$Minutes.' min';
}
$Levels--;
}
if($Return == '') {
$Return = 'Just now';
} elseif (!isset($HideAgo)) {
$Return .= ' ago';
}
if ($Span) {
return '<span class="time" title="'.date('M d Y, H:i', $TimeStamp).'">'.$Return.'</span>';
} else {
return $Return;
}
}
/* SQL utility functions */
function time_plus($Offset) {
return date('Y-m-d H:i:s', time()+$Offset);
}
function time_minus($Offset, $Fuzzy = false) {
if($Fuzzy) {
return date('Y-m-d 00:00:00', time()-$Offset);
} else {
return date('Y-m-d H:i:s', time()-$Offset);
}
}
function sqltime() {
return date('Y-m-d H:i:s');
}
function validDate($DateString) {
$DateTime = explode(" ", $DateString);
if(count($DateTime) != 2) return false;
list($Date, $Time) = $DateTime;
$SplitTime = explode(":", $Time);
if(count($SplitTime) != 3) return false;
list($H, $M, $S) = $SplitTime;
if($H != 0 && !(is_number($H) && $H < 24 && $H >= 0)) return false;
if($M != 0 && !(is_number($M) && $M < 60 && $M >= 0)) return false;
if($S != 0 && !(is_number($S) && $S < 60 && $S >= 0)) return false;
$SplitDate = explode("-", $Date);
if(count($SplitDate) != 3) return false;
list($Y, $M, $D) = $SplitDate;
return checkDate($M, $D, $Y);
}
?>

308
classes/class_torrent.php Normal file
View File

@ -0,0 +1,308 @@
<?
/*******************************************************************************
|~~~~ Gazelle bencode parser ~~~~|
--------------------------------------------------------------------------------
Welcome to the Gazelle bencode parser. bencoding is the way of encoding data
that bittorrent uses in torrent files. When we read the torrent files, we get
one long string that must be parsed into a format we can easily edit - that's
where this file comes into play.
There are 4 data types in bencode:
* String
* Int
* List - array without keys
- like array('value', 'value 2', 'value 3', 'etc')
* Dictionary - array with string keys
- like array['key 1'] = 'value 1'; array['key 2'] = 'value 2';
Before you go any further, we recommend reading the sections on bencoding and
metainfo file structure here: http://wiki.theory.org/BitTorrentSpecification
//----- How we store the data -----//
* Strings
- Stored as php strings. Not difficult to remember.
* Integers
- Stored as php ints
- must be casted with (int)
* Lists
- Stored as a BENCODE_LIST object.
- The actual list is in BENCODE_LIST::$Val, as an array with incrementing integer indices
- The list in BENCODE_LIST::$Val is populated by the BENCODE_LIST::dec() function
* Dictionaries
- Stored as a BENCODE_DICT object.
- The actual list is in BENCODE_DICT::$Val, as an array with string indices
- The list in BENCODE_DICT::$Val is populated by the BENCODE_DICT::dec() function
//----- BENCODE_* Objects -----//
Lists and dictionaries are stored as objects. They each have the following
functions:
* decode(Type, $Key)
- Decodes ANY bencoded element, given the type and the key
- Gets the position and string from $this
* encode($Val)
- Encodes ANY non-bencoded element, given the value
* dec()
- Decodes either a dictionary or a list, depending on where it's called from
- Uses the decode() function quite a bit
* enc()
- Encodes either a dictionary or a list, depending on where it's called from
- Relies mostly on the encode() function
Finally, as all torrents are just large dictionaries, the TORRENT class extends
the BENCODE_DICT class.
*******************************************************************************/
class BENCODE {
var $Val; // Decoded array
var $Pos = 1; // Pointer that indicates our position in the string
var $Str = ''; // Torrent string
function __construct($Val, $IsParsed = false){
if(!$IsParsed) {
$this->Str = $Val;
$this->dec();
} else {
$this->Val = $Val;
}
}
// Decode an element based on the type. The type is really just an indicator.
function decode($Type, $Key){
if(is_number($Type)) { // Element is a string
// Get length of string
$StrLen = $Type;
while($this->Str[$this->Pos+1]!=':'){
$this->Pos++;
$StrLen.=$this->Str[$this->Pos];
}
$this->Val[$Key] = substr($this->Str, $this->Pos+2, $StrLen);
$this->Pos+=$StrLen;
$this->Pos+=2;
} elseif($Type == 'i') { // Element is an int
$this->Pos++;
// Find end of integer (first occurance of 'e' after position)
$End = strpos($this->Str, 'e', $this->Pos);
// Get the integer, and - IMPORTANT - cast it as an int, so we know later that it's an int and not a string
$this->Val[$Key] = (int)substr($this->Str, $this->Pos, $End-$this->Pos);
$this->Pos = $End+1;
} elseif($Type == 'l') { // Element is a list
$this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
$this->Pos += $this->Val[$Key]->Pos;
} elseif($Type == 'd') { // Element is a dictionary
$this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
$this->Pos += $this->Val[$Key]->Pos;
// Sort by key to respect spec
ksort($this->Val[$Key]->Val);
} else {
die('Invalid torrent file');
}
}
function encode($Val){
if(is_int($Val)) { // Integer
return 'i'.$Val.'e';
} elseif(is_string($Val)) {
return strlen($Val).':'.$Val;
} elseif(is_object($Val)) {
return $Val->enc();
} else {
return 'fail';
}
}
}
class BENCODE_LIST extends BENCODE {
function enc(){
$Str = 'l';
reset($this->Val);
foreach ($this->Val as $Value) {
$Str.=$this->encode($Value);
}
return $Str.'e';
}
// Decode a list
function dec(){
$Key = 0; // Array index
$Length = strlen($this->Str);
while($this->Pos<$Length){
$Type = $this->Str[$this->Pos];
// $Type now indicates what type of element we're dealing with
// It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
if($Type == 'e') { // End of list
$this->Pos += 1;
unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
return;
}
// Decode the bencoded element.
// This function changes $this->Pos and $this->Val, so you don't have to.
$this->decode($Type, $Key);
++ $Key;
}
return true;
}
}
class BENCODE_DICT extends BENCODE {
function enc(){
$Str = 'd';
reset($this->Val);
foreach ($this->Val as $Key => $Value) {
$Str.=strlen($Key).':'.$Key.$this->encode($Value);
}
return $Str.'e';
}
// Decode a dictionary
function dec(){
$Length = strlen($this->Str);
while($this->Pos<$Length) {
if($this->Str[$this->Pos] == 'e') { // End of dictionary
$this->Pos += 1;
unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
return;
}
// Get the dictionary key
// Length of the key, in bytes
$KeyLen = $this->Str[$this->Pos];
// Allow for multi-digit lengths
while($this->Str[$this->Pos+1]!=':' && $this->Pos+1<$Length) {
$this->Pos++;
$KeyLen.=$this->Str[$this->Pos];
}
// $this->Pos is now on the last letter of the key length
// Adding 2 brings it past that character and the ':' to the beginning of the string
$this->Pos+=2;
// Get the name of the key
$Key = substr($this->Str, $this->Pos, $KeyLen);
// Move the position past the key to the beginning of the element
$this->Pos+=$KeyLen;
$Type = $this->Str[$this->Pos];
// $Type now indicates what type of element we're dealing with
// It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
// Decode the bencoded element.
// This function changes $this->Pos and $this->Val, so you don't have to.
$this->decode($Type, $Key);
}
return true;
}
}
class TORRENT extends BENCODE_DICT {
function dump() {
// Convenience function used for testing and figuring out how we store the data
print_r($this->Val);
}
function dump_data() {
// Function which serializes $this->Val for storage
return base64_encode(serialize($this->Val));
}
/*
To use this, please remove the announce-list unset in make_private and be sure to still set_announce_url for backwards compatibility
function set_multi_announce() {
$Trackers = func_get_args();
$AnnounceList = new BENCODE_LIST(array(),true);
foreach ($Trackers as $Tracker) {
$SubList = new BENCODE_LIST(array($Tracker),true);
unset($SubList->Str);
$AnnounceList->Val[] = $SubList;
}
$this->Val['announce-list'] = $AnnounceList;
}
*/
function set_announce_url($Announce) {
$this->Val['announce'] = $Announce;
}
// Returns an array of:
// * the files in the torrent
// * the total size of files described therein
function file_list() {
$FileList = array();
if(!$this->Val['info']->Val['files']) { // Single file mode
$TotalSize = $this->Val['info']->Val['length'];
$FileList[]= array($this->Val['info']->Val['length'], $this->Val['info']->Val['name']);
} else { // Multiple file mode
$FileNames = array();
$TotalSize = 0;
$Files = $this->Val['info']->Val['files']->Val;
foreach($Files as $File) {
$TotalSize+=$File->Val['length'];
$FileSize = $File->Val['length'];
$FileName = implode('/',$File->Val['path']->Val);
$FileList[] = array($FileSize, $FileName);
$FileNames[] = $FileName;
}
array_multisort($FileNames, $FileList);
}
return array($TotalSize, $FileList);
}
function make_private() {
//----- The following properties do not affect the infohash:
// anounce-list is an unofficial extension to the protocol
// that allows for multiple trackers per torrent
unset($this->Val['announce-list']);
// Bitcomet & Azureus cache peers in here
unset($this->Val['nodes']);
// Azureus stores the dht_backup_enable flag here
unset($this->Val['azureus_properties']);
// Remove web-seeds
unset($this->Val['url-list']);
// Remove libtorrent resume info
unset($this->Val['libtorrent_resume']);
//----- End properties that do not affect the infohash
if ($this->Val['info']->Val['private']) {
return true; // Torrent is private
} else {
// Torrent is not private!
// add private tracker flag
$this->Val['info']->Val['private'] = 1;
return false;
}
}
}
?>

View File

@ -0,0 +1,292 @@
<?
/*******************************************************************************
|~~~~ Gazelle bencode parser ~~~~|
--------------------------------------------------------------------------------
Welcome to the Gazelle bencode parser. bencoding is the way of encoding data
that bittorrent uses in torrent files. When we read the torrent files, we get
one long string that must be parsed into a format we can easily edit - that's
where this file comes into play.
There are 4 data types in bencode:
* String
* Int
* List - array without keys
- like array('value', 'value 2', 'value 3', 'etc')
* Dictionary - array with string keys
- like array['key 1'] = 'value 1'; array['key 2'] = 'value 2';
Before you go any further, we recommend reading the sections on bencoding and
metainfo file structure here: http://wiki.theory.org/BitTorrentSpecification
//----- How we store the data -----//
* Strings
- Stored as php strings. Not difficult to remember.
* Integers
- Stored as php strings with an [*INT*] marker
- Can be stored an an int on 64 bit boxes for uber speed (we do this)
- If stored as an int on 32 bit boxes, it won't allow for any size over 2 gigs
* Lists
- Stored as a BENCODE_LIST object.
- The actual list is in BENCODE_LIST::$Val, as an array with incrementing integer indices
- The list in BENCODE_LIST::$Val is populated by the BENCODE_LIST::dec() function
* Dictionaries
- Stored as a BENCODE_DICT object.
- The actual list is in BENCODE_DICT::$Val, as an array with incrementing integer indices
- The list in BENCODE_DICT::$Val is populated by the BENCODE_DICT::dec() function
//----- BENCODE_* Objects -----//
Lists and dictionaries are stored as objects. They each have the following
functions:
* decode(Type, $Key)
- Decodes ANY bencoded element, given the type and the key
- Gets the position and string from $this
* encode($Val)
- Encodes ANY non-bencoded element, given the value
* dec()
- Decodes either a dictionary or a list, depending on where it's called from
- Uses the decode() function quite a bit
* enc()
- Encodes either a dictionary or a list, depending on where it's called from
- Relies mostly on the encode() function
Finally, as all torrents are just large dictionaries, the TORRENT class extends
the BENCODE_DICT class.
**Note** The version we run doesn't store ints as strings marked with [*INT*]
We store them as php integers. You can do this too for added speed and reduced
hackery, if you're running a 64 bit box, or if you're running a 32 bit box and
don't care about files larger than 2 gigs. The system with the [*INT*]s was
coded up in around 4 minutes for STC when we discovered this problem, then
discovered that floats aren't accurate enough to use. :(
*******************************************************************************/
class BENCODE {
var $Val; // Decoded array
var $Pos = 1; // Pointer that indicates our position in the string
var $Str = ''; // Torrent string
function BENCODE($Val){
$this->Str = $Val;
$this->dec();
}
// Decode an element based on the type
function decode($Type, $Key){
if(ctype_digit($Type)) { // Element is a string
// Get length of string
$StrLen = $Type;
while($this->Str[$this->Pos+1]!=':'){
$this->Pos++;
$StrLen.=$this->Str[$this->Pos];
}
$this->Val[$Key] = substr($this->Str, $this->Pos+2, $StrLen);
$this->Pos+=$StrLen;
$this->Pos+=2;
} elseif($Type == 'i') { // Element is an int
$this->Pos++;
// Find end of integer (first occurance of 'e' after position)
$End = strpos($this->Str, 'e', $this->Pos);
// Get the integer, and mark it as an int (on our version 64 bit box, we cast it to an int)
$this->Val[$Key] = '[*INT*]'.substr($this->Str, $this->Pos, $End-$this->Pos);
$this->Pos = $End+1;
} elseif($Type == 'l') { // Element is a list
$this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
$this->Pos += $this->Val[$Key]->Pos;
} elseif($Type == 'd') { // Element is a dictionary
$this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
$this->Pos += $this->Val[$Key]->Pos;
// Sort by key to respect spec
ksort($this->Val[$Key]->Val);
} else {
die('Invalid torrent file');
}
}
function encode($Val){
if(is_string($Val)) {
if(substr($Val, 0, 7) == '[*INT*]') {
return 'i'.substr($Val,7).'e';
} else {
return strlen($Val).':'.$Val;
}
} elseif(is_object($Val)) {
return $Val->enc();
} else {
return 'fail';
}
}
}
class BENCODE_LIST extends BENCODE {
function enc(){
$Str = 'l';
reset($this->Val);
while(list($Key, $Value) = each($this->Val)) {
$Str.=$this->encode($Value);
}
return $Str.'e';
}
// Decode a list
function dec(){
$Key = 0; // Array index
$Length = strlen($this->Str);
while($this->Pos<$Length){
$Type = $this->Str[$this->Pos];
// $Type now indicates what type of element we're dealing with
// It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
if($Type == 'e') { // End of list
$this->Pos += 1;
unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
return;
}
// Decode the bencoded element.
// This function changes $this->Pos and $this->Val, so you don't have to.
$this->decode($Type, $Key);
++ $Key;
}
return true;
}
}
class BENCODE_DICT extends BENCODE {
function enc(){
$Str = 'd';
reset($this->Val);
while(list($Key, $Value) = each($this->Val)) {
$Str.=strlen($Key).':'.$Key.$this->encode($Value);
}
return $Str.'e';
}
// Decode a dictionary
function dec(){
$Length = strlen($this->Str);
while($this->Pos<$Length) {
if($this->Str[$this->Pos] == 'e') { // End of dictionary
$this->Pos += 1;
unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
return;
}
// Get the dictionary key
// Length of the key, in bytes
$KeyLen = $this->Str[$this->Pos];
// Allow for multi-digit lengths
while($this->Str[$this->Pos+1]!=':' && $this->Pos+1<$Length) {
$this->Pos++;
$KeyLen.=$this->Str[$this->Pos];
}
// $this->Pos is now on the last letter of the key length
// Adding 2 brings it past that character and the ':' to the beginning of the string
$this->Pos+=2;
// Get the name of the key
$Key = substr($this->Str, $this->Pos, $KeyLen);
// Move the position past the key to the beginning of the element
$this->Pos+=$KeyLen;
$Type = $this->Str[$this->Pos];
// $Type now indicates what type of element we're dealing with
// It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
// Decode the bencoded element.
// This function changes $this->Pos and $this->Val, so you don't have to.
$this->decode($Type, $Key);
}
return true;
}
}
class TORRENT extends BENCODE_DICT {
function dump() {
// Convenience function used for testing and figuring out how we store the data
print_r($this->Val);
}
function dump_data() {
// Function which serializes $this->Val for storage
return base64_encode(serialize($this->Val));
}
function set_announce_url($Announce) {
$this->Val['announce'] = $Announce;
}
// Returns an array of:
// * the files in the torrent
// * the total size of files described therein
function file_list() {
$FileList = array();
if(!$this->Val['info']->Val['files']) { // Single file mode
$TotalSize = substr($this->Val['info']->Val['length'],7);
$FileList[]= array($TotalSize, $this->Val['info']->Val['name']);
} else { // Multiple file mode
$TotalSize = 0;
$Files = $this->Val['info']->Val['files']->Val;
foreach($Files as $File) {
$TotalSize+=substr($File->Val['length'], 7);
$FileSize = substr($File->Val['length'],7);
$FileName = implode('/',$File->Val['path']->Val);
$FileList[]=array($FileSize, $FileName);
}
}
return array($TotalSize, $FileList);
}
function make_private() {
// Might as well take care of some useless shit
// anounce-list is an unofficial extension to the protocol that allows for multiple trackers per torrent
unset($this->Val['announce-list']);
// Bitcomet & Azureus cache peers in here
unset($this->Val['nodes']);
// Azureus stores the dht_backup_enable flag here
unset($this->Val['azureus_properties']);
// Azureus stores the dht_backup_enable flag here
unset($this->Val['libtorrent_resume']);
if (!empty($this->Val['info']->Val['private']) && $this->Val['info']->Val['private'] == '[*INT*]1') {
return true;
} else {
// Torrent is not private!
// add private tracker flag
$this->Val['info']->Val['private'] = '[*INT*]1';
return false;
}
}
}
?>

View File

@ -0,0 +1,656 @@
<?
/********************************************************************************
************ Torrent form class *************** upload.php and torrents.php ****
********************************************************************************
** This class is used to create both the upload form, and the 'edit torrent' **
** form. It is broken down into several functions - head(), foot(), **
** music_form() [music], audiobook_form() [Audiobooks and comedy], and **
** simple_form() [everything else]. **
** **
** When it is called from the edit page, the forms are shortened quite a bit. **
** **
********************************************************************************/
class TORRENT_FORM {
var $Categories = array();
var $Formats = array();
var $Bitrates = array();
var $Media = array();
var $NewTorrent = false;
var $Torrent = array();
var $Error = false;
var $TorrentID = false;
var $Disabled = '';
function TORRENT_FORM($Torrent = false, $Error = false, $NewTorrent = true) {
$this->NewTorrent = $NewTorrent;
$this->Torrent = $Torrent;
$this->Error = $Error;
global $Categories, $Formats, $Bitrates, $Media, $TorrentID;
$this->Categories = $Categories;
$this->Formats = $Formats;
$this->Bitrates = $Bitrates;
$this->Media = $Media;
$this->TorrentID = $TorrentID;
if($this->Torrent && $this->Torrent['GroupID']) {
$this->Disabled = ' disabled="disabled"';
}
}
function head() {
global $LoggedUser;
?>
<div class="thin">
<? if($this->NewTorrent) { ?>
<p style="text-align: center;">
Your personal announce url is:<br />
<input type="text" value="<?= ANNOUNCE_URL.'/'.$LoggedUser['torrent_pass'].'/announce'?>" size="71" onfocus="this.select()" />
</p>
<? }
if($this->Error) {
echo '<p style="color: red;text-align:center;">'.$this->Error.'</p>';
}
?>
<form action="" enctype="multipart/form-data" method="post" id="upload_table" onsubmit="$('#post').raw().disabled = 'disabled'">
<div>
<input type="hidden" name="submit" value="true" />
<input type="hidden" name="auth" value="<?=$LoggedUser['AuthKey']?>" />
<? if(!$this->NewTorrent) { ?>
<input type="hidden" name="action" value="takeedit" />
<input type="hidden" name="torrentid" value="<?=display_str($this->TorrentID)?>" />
<input type="hidden" name="type" value="<?=display_str($this->Torrent['CategoryID'])?>" />
<? } else if($this->Torrent && $this->Torrent['GroupID']) { ?>
<input type="hidden" name="groupid" value="<?=display_str($this->Torrent['GroupID'])?>" />
<input type="hidden" name="type" value="Music" />
<? } else if($this->Torrent && $this->Torrent['RequestID']) { ?>
<input type="hidden" name="requestid" value="<?=display_str($this->Torrent['RequestID'])?>" />
<? } ?>
</div>
<? if($this->NewTorrent) { ?>
<table cellpadding="3" cellspacing='1' border='0' class='border' width="100%">
<tr>
<td class="label">
Torrent file
</td>
<td>
<input id="file" type="file" name="file_input" size="50" />
</td>
</tr>
<tr>
<td class="label">
Type
</td>
<td>
<select id="categories" name="type" onchange="Categories()"<?=$this->Disabled?>>
<? foreach(display_array($this->Categories) as $Index => $Cat) {
echo "<option value='$Index'";
if($Cat == $this->Torrent['CategoryName']) { echo " selected='selected'"; }
echo ">";
echo $Cat;
echo "</option>\n";
}
?>
</select>
</td>
</tr>
</table>
<? }//if ?>
<div id="dynamic_form">
<? } // function head
function foot() {
$Torrent = $this->Torrent;
?>
</div>
<table cellpadding="3" cellspacing="1" border="0" class="border slice" width="100%">
<? if(!$this->NewTorrent) {
if(check_perms('torrents_freeleech')) {
?>
<tr id="freetorrent">
<td class="label">Freeleech</td>
<td>
<input type="checkbox" name="freeleech"<?=$Torrent['FreeTorrent'] ? ' checked="checked"' : ''?> /> Checking this box will make the torrent freeleech. Don't abuse it.
</td>
</tr>
<tr id="grace">
<td class="label">Extended Grace</td>
<td>
<input type="checkbox" name="extendedgrace"<?=$Torrent['ExtendedGrace']? ' checked="checked"' : ''?> /> Checking this box extendes the grace period for this torrent.
</td>
</tr>
<?
}
}
?>
<tr>
<td colspan="2" style="text-align: center;">
<p>Be sure that your torrent is approved by the <a href="rules.php?p=upload">rules</a>. Not doing this will result in a <strong>warning</strong> or <strong>worse</strong>.</p>
<? if($this->NewTorrent) { ?>
<p>After uploading the torrent, you will have a one hour grace period during which no one other than you can fill requests with this torrent. Make use of this time wisely, and search the requests. </p>
<? } ?>
<input id="post" type="submit" <? if($this->NewTorrent) { echo "value=\"Upload torrent\""; } else { echo "value=\"Edit torrent\"";} ?> />
</td>
</tr>
</table>
</form>
</div>
<? } //function foot
function music_form($GenreTags) {
$Torrent = $this->Torrent;
$IsRemaster = !empty($Torrent['Remastered']);
$UnknownRelease = !$this->NewTorrent && $IsRemaster && !$Torrent['RemasterYear'];
if($Torrent['GroupID']) {
global $DB;
$DB->query("SELECT ID,
RemasterYear,
RemasterTitle,
RemasterRecordLabel,
RemasterCatalogueNumber
FROM torrents
WHERE GroupID = ".$Torrent['GroupID']."
AND Remastered = '1'
AND RemasterYear != 0
ORDER BY RemasterYear DESC,
RemasterTitle DESC,
RemasterRecordLabel DESC,
RemasterCatalogueNumber DESC");
if($DB->record_count() > 0) {
$GroupRemasters = $DB->to_array(false, MYSQLI_BOTH, false);
}
}
$HasLog = $Torrent['HasLog'];
$HasCue = $Torrent['HasCue'];
$BadTags = $Torrent['BadTags'];
$BadFolders = $Torrent['BadFolders'];
$BadFiles = $Torrent['BadFiles'];
global $ReleaseTypes;
?>
<table cellpadding="3" cellspacing="1" border="0" class="border<? if($this->NewTorrent) { echo ' slice'; }?>" width="100%">
<? if($this->NewTorrent) { ?>
<tr id="artist_tr">
<td class="label">Artist(s)</td>
<td id="artistfields">
<p id="vawarning" class="hidden">Please use the multiple artists feature rather than adding 'Various Artists' as an artist, read <a href='wiki.php?action=article&amp;id=369'>this</a> for more information on why.</p>
<? if(!empty($Torrent['Artists'])) {
foreach($Torrent['Artists'] as $Importance => $Artists) {
foreach($Artists as $Artist) {
?>
<input type="text" id="artist" name="artists[]" size="45" value="<?=display_str($Artist['name']) ?>" onblur="CheckVA();" <?=$this->Disabled?>/>
<select id="importance" name="importance[]" <?=$this->Disabled?>>
<option value="1"<?=($Importance == '1' ? ' selected="selected"' : '')?>>Main</option>
<option value="2"<?=($Importance == '2' ? ' selected="selected"' : '')?>>Guest</option>
<option value="3"<?=($Importance == '3' ? ' selected="selected"' : '')?>>Remixer</option>
</select>
<br />
<? }
}
} else {
?>
<input type="text" id="artist" name="artists[]" size="45" onblur="CheckVA();"<?=$this->Disabled?>/>
<select id="importance" name="importance[]" <?=$this->Disabled?>>
<option value="1">Main</option>
<option value="2">Guest</option>
<option value="3">Remixer</option>
</select>
[<a href="#" onclick="AddArtistField();return false;">+</a>] [<a href="#" onclick="RemoveArtistField();return false;">-</a>]
<?
}
?>
</td>
</tr>
<tr id="title_tr">
<td class="label">Album title:</td>
<td>
<input type="text" id="title" name="title" size="60" value="<?=display_str($Torrent['Title']) ?>"<?=$this->Disabled?>/>
<p class="min_padding">Do not include the words remaster, re-issue, MSFL Gold, limited edition, bonus tracks, bonus disc or country specific information in this field. That belongs in the edition information fields below, see <a href="wiki.php?action=article&amp;id=159">this</a> for further information. Also remember to use the correct capitalization for your upload. See the <a href="wiki.php?action=article&amp;id=317">Capitalization Guidelines</a> for more information.
</td>
</tr>
<tr id="year_tr">
<td class="label">
<span id="year_label_not_remaster"<? if($IsRemaster) { echo ' class="hidden"';}?>>Year</span>
<span id="year_label_remaster"<? if(!$IsRemaster) { echo ' class="hidden"';}?>>Year of original release</span>
</td>
<td>
<p id="yearwarning" class="hidden">You have entered a year for a release which predates the medium's availibility. You will need to change the year, enter additional edition information or if this information cannot be provided, select the 'Unknown Release' checkbox below</p>
<input type="text" id="year" name="year" size="5" value="<?=display_str($Torrent['Year']) ?>"<?=$this->Disabled?> onblur="CheckYear();" /> This is the year of the original release.
</td>
</tr>
<tr id="label_tr">
<td class="label">Record Label (Optional):</td>
<td>
<input type="text" id="record_label" name="record_label" size="40" value="<?=display_str($Torrent['RecordLabel']) ?>"<?=$this->Disabled?> />
</td>
</tr>
<tr id="catalogue_tr">
<td class="label">Catalogue Number (Optional):</td>
<td>
<input type="text" id="catalogue_number" name="catalogue_number" size="40" value="<?=display_str($Torrent['CatalogueNumber']) ?>"<?=$this->Disabled?> />
</td>
</tr>
<tr id="releasetype_tr">
<td class="label">
<span id="releasetype_label">Release type</span>
</td>
<td>
<select id="releasetype" name="releasetype"<?=$this->Disabled?>>
<option>---</option>
<?
foreach ($ReleaseTypes as $Key => $Val) {
echo "<option value='$Key'";
if($Key == $Torrent['ReleaseType']) { echo " selected='selected'"; }
echo ">";
echo $Val;
echo "</option>\n";
}
?>
</select> Please take the time to fill this out properly (try searching <a href="http://musicbrainz.org/search.html">musicbrainz</a>).
</td>
</tr>
<? } ?>
<tr>
<td class="label">Edition information</td>
<td>
<input type="checkbox" id="remaster" name="remaster"<? if($IsRemaster) { echo " checked='checked' ";}?> onclick="Remaster();<?if($this->NewTorrent) {?> CheckYear();<? } ?>" />
Check this box if this torrent is a different release to the original, for example a limited or country specific edition or a release that includes additional bonus tracks or is a bonus disc.
<div id="remaster_true"<? if(!$IsRemaster) { echo ' class="hidden"';}?>>
<? if(check_perms('edit_unknowns') || $LoggedUser['ID'] == $Torrent['UserID']) { ?>
<br />
<input type="checkbox" id="unknown" name="unknown"<? if($UnknownRelease) { echo " checked='checked' ";}?> onclick="<?if($this->NewTorrent) {?> CheckYear();<? } ?>ToggleUnknown();"/> Unknown Release
<? } ?>
<br /><br />
<? if(!empty($GroupRemasters)) { ?>
<input type="hidden" id="json_remasters" value="<?=display_str(json_encode($GroupRemasters))?>" />
<select id="groupremasters" name="groupremasters" onchange="GroupRemaster()"<? if($UnknownRelease) { echo " disabled";}?>>
<option value="">-------</option>
<?
$LastLine = "";
foreach($GroupRemasters as $Index => $Remaster) {
$Line = $Remaster['RemasterYear']." / ".$Remaster['RemasterTitle']." / ".$Remaster['RemasterRecordLabel']." / ".$Remaster['RemasterCatalogueNumber'];
if($Line != $LastLine) {
$LastLine = $Line;
?>
<option value="<?=$Index?>"<?=($Remaster['ID'] == $this->TorrentID) ? ' selected="selected"' : ''?>><?=$Line?></option>
<?
}
}
?>
</select>
<br />
<? } ?>
<br />
<strong>Year (Required):</strong>
<input type="text" id="remaster_year" name="remaster_year" size="5" value="<? if($Torrent['RemasterYear']) { echo display_str($Torrent['RemasterYear']);} ?>"<? if($UnknownRelease) { echo " disabled";}?> /> <br />
<strong>Title:</strong>
<input type="text" id="remaster_title" name="remaster_title" size="50" value="<?=display_str($Torrent['RemasterTitle']) ?>"<? if($UnknownRelease) { echo " disabled";}?> />
<p class="min_padding">Title of the release, eg. <i>'Deluxe Edition' or 'Remastered'</i>.</p>
<strong>Record Label:</strong>
<input type="text" id="remaster_record_label" name="remaster_record_label" size="50" value="<?=display_str($Torrent['RemasterRecordLabel']) ?>"<? if($UnknownRelease) { echo " disabled";}?> />
<p class="min_padding">This is for the record label of the <strong>release</strong> (It may differ from the original).</p>
<strong>Catalogue Number:</strong>
<input type="text" id="remaster_catalogue_number" name="remaster_catalogue_number" size="50" value="<?=display_str($Torrent['RemasterCatalogueNumber']) ?>"<? if($UnknownRelease) { echo " disabled";}?> />
<p class="min_padding">This is for the catalogue number of the <strong>release</strong>.</p>
</div>
</td>
</tr>
<tr>
<td class="label">Scene</td>
<td>
<input type="checkbox" id="scene" name="scene" <? if($Torrent['Scene']) { echo "checked='checked' ";}?>/>
Check this only if this is a 'scene release'. If you ripped it yourself, it is <strong>not</strong> a scene release. <br />If you are not sure, <strong>DO NOT</strong> check it, you will be penalized. For information on the scene, visit <a href="http://en.wikipedia.org/wiki/Scene_%28software%29">Wikipedia</a>.
</td>
</tr>
<tr>
<td class="label">Format</td>
<td>
<select id="format" name="format" onchange="Format()">
<option>---</option>
<? foreach(display_array($this->Formats) as $Format) {
echo "<option value='$Format'";
if($Format == $Torrent['Format']) { echo " selected='selected'"; }
echo ">";
echo $Format;
echo "</option>\n";
// <option value='$Format' selected='selected'>$Format</option>
}
?>
</select>
</td>
</tr>
<tr>
<td class="label">Bitrate</td>
<td>
<select id="bitrate" name="bitrate" onchange="Bitrate()">
<option value="">---</option>
<? if($Torrent['Bitrate'] && !in_array($Torrent['Bitrate'], $this->Bitrates)) {
$OtherBitrate = true;
if(substr($Torrent['Bitrate'], strlen($Torrent['Bitrate']) - strlen(" (VBR)")) == " (VBR)") {
$Torrent['Bitrate'] = substr($Torrent['Bitrate'], 0, strlen($Torrent['Bitrate'])-6);
$VBR = true;
}
} else {
$OtherBitrate = false;
}
// See if they're the same bitrate
// We have to do this screwery because '(' is a regex character.
$SimpleBitrate = explode(' ', $Torrent['Bitrate']);
$SimpleBitrate = $SimpleBitrate[0];
foreach(display_array($this->Bitrates) as $Bitrate) {
echo "<option value='$Bitrate'";
if(($SimpleBitrate && preg_match('/^'.$SimpleBitrate.'.*/', $Bitrate)) || ($OtherBitrate && $Bitrate == "Other")) {
echo ' selected="selected"';
}
echo ">";
echo $Bitrate;
echo "</option>\n";
} ?>
</select>
<span id="other_bitrate_span"<? if(!$OtherBitrate) { echo ' class="hidden"'; } ?>>
<input type="text" name="other_bitrate" size="5" id="other_bitrate"<? if($OtherBitrate) { echo " value='".display_str($Torrent['Bitrate'])."'";} ?> onchange="AltBitrate()" />
<input type="checkbox" id="vbr" name="vbr"<? if(isset($VBR)) { echo ' checked="checked"'; } ?> /> (VBR)
</span>
</td>
</tr>
<tr>
<td class="label">Media</td>
<td>
<select name="media" onchange="Media(); CheckYear();" id="media">
<option>---</option>
<? foreach($this->Media as $Media) {
echo "<option value='$Media'";
if(isset($Torrent['Media']) && $Media == $Torrent['Media']) { echo " selected='selected'"; }
echo ">";
echo $Media;
echo "</option>\n";
}
?>
</select>
<span id="cassette_true" class="hidden"><strong style="color:red;">Do NOT upload a cassette rip without first getting approval from a moderator!</strong></span>
</td>
</tr>
<?
if($this->NewTorrent) { ?>
<tr id="upload_logs" class="hidden">
<td class="label">
Log Files
</td>
<td id="logfields">
Check your log files here before uploading: <a href="logchecker.php">logchecker.php</a><br />
<input id="file" type="file" name="logfiles[]" size="50" /> [<a href="javascript:;" onclick="AddLogField();">+</a>] [<a href="javascript:;" onclick="RemoveLogField();">-</a>]
</td>
</tr>
<?
} ?>
<? if(!$this->NewTorrent && check_perms('users_mod')) { ?>
<tr>
<td class="label">Log/Cue</td>
<td>
<input type="checkbox" id="flac_log" name="flac_log"<? if($HasLog) { echo " checked='checked'";}?>/> Check this box if the torrent has (or should have) a log file.<br />
<input type="checkbox" id="flac_cue" name="flac_cue"<? if($HasCue) { echo " checked='checked'";}?>/> Check this box if the torrent has (or should have) a cue file.<br />
<?
}
global $LoggedUser;
if ((check_perms('users_mod') || $LoggedUser['ID'] == $Torrent['UserID']) && ($Torrent['LogScore'] == 100 || $Torrent['LogScore'] == 99)) {
$DB->query("SELECT LogID FROM torrents_logs_new where TorrentID = ".$this->TorrentID." AND Log LIKE 'EAC extraction logfile%' AND (Adjusted = '0' OR Adjusted = '')");
list($LogID) = $DB->next_record();
if ($LogID) {
if (!check_perms('users_mod')) {
?>
<tr>
<td class="label">Trumpable</td>
<td>
<?
}
?>
<input type="checkbox" id="make_trumpable" name="make_trumpable"<? if ($Torrent['LogScore'] == 99) { echo " checked='checked'";}?>/>Check this box if you want this torrent to be trumpable (subtracts 1 point).
<?
if (!check_perms('users_mod')) {
?> </td>
</tr>
<?
}
}
}
if(!$this->NewTorrent && check_perms('users_mod')) {?>
</td>
</tr>
<?/* if($HasLog) { ?>
<tr>
<td class="label">Log Score</td>
<td>
<input type="text" name="log_score" size="5" id="log_score" value="<?=display_str($Torrent['LogScore']) ?>" />
</td>
</tr>
<tr>
<td class="label">Log Adjustment Reason</td>
<td>
<textarea name="adjustment_reason" id="adjustment_reason" cols="60" rows="8"><?=display_str($Torrent['AdjustmentReason']); ?></textarea>
<p class="min_padding">Contains reason for adjusting a score. <b>This field is displayed on the torrent page</b>.</p>
</td>
</tr>
<? }*/?>
<tr>
<td class="label">Bad Tags</td>
<td>
<input type="checkbox" id="bad_tags" name="bad_tags"<? if($BadTags) { echo " checked='checked'";}?>/> Check this box if the torrent has bad tags.
</td>
</tr>
<tr>
<td class="label">Bad Folder Names</td>
<td>
<input type="checkbox" id="bad_folders" name="bad_folders"<? if($BadFolders) { echo " checked='checked'";}?>/> Check this box if the torrent has bad folder names.
</td>
</tr>
<tr>
<td class="label">Bad File Names</td>
<td>
<input type="checkbox" id="bad_files" name="bad_files"<? if ($BadFiles) {echo " checked='checked'";}?>/> Check this box if the torrent has bad file names.
</td>
</tr>
<? } ?>
<? if($this->NewTorrent) { ?>
<tr>
<td class="label">Tags</td>
<td>
<? if($GenreTags) { ?>
<select id="genre_tags" name="genre_tags" onchange="add_tag();return false;" <?=$this->Disabled?>>
<option>---</option>
<? foreach(display_array($GenreTags) as $Genre) { ?>
<option value="<?=$Genre ?>"><?=$Genre ?></option>
<? } ?>
</select>
<? } ?>
<input type="text" id="tags" name="tags" size="40" value="<?=display_str($Torrent['TagList']) ?>" <?=$this->Disabled?>/>
<br />
Tags should be comma separated, and you should use a period ('.') to separate words inside a tag - eg. '<strong style="color:green;">hip.hop</strong>'.
<br /><br />
There is a list of official tags to the left of the text box. Please use these tags instead of 'unofficial' tags (eg. use the official '<strong style="color:green;">drum.and.bass</strong>' tag, instead of an unofficial '<strong style="color:red;">dnb</strong>' tag.)
<br /><br />
Avoid abbreviations if at all possible. So instead of tagging an album as '<strong style="color:red;">alt</strong>', tag it as '<strong style="color:green;">alternative</strong>'. Make sure that you use correct spelling.
<br /><br />
Avoid using multiple synonymous tags. Using both '<strong style="color:red;">prog.rock</strong>' and '<strong style="color:green;">progressive.rock</strong>' is redundant and annoying - just use the official '<strong style="color:green;">progressive.rock</strong>' tag.
<br /><br />
Don't use 'useless' tags, such as '<strong style="color:red;">seen.live</strong>', '<strong style="color:red;">awesome</strong>', '<strong style="color:red;">rap</strong>' (is encompassed by '<strong style="color:green;">hip.hop</strong>'), etc. If an album is live, you can tag it as '<strong style="color:green;">live</strong>'.
<br /><br />
Only tag information on the album itself - NOT THE INDIVIDUAL RELEASE. Tags such as '<strong style="color:red;">v0</strong>', '<strong style="color:red;">eac</strong>', '<strong style="color:red;">vinyl</strong>', '<strong style="color:red;">from.oink</strong>' etc are strictly forbidden. Remember that these tags will be used for other versions of the same album.
<br /><br />
<strong>You should be able to build up a list of tags using only the official tags to the left of the text box. If you are in any doubt about whether or not a tag is acceptable, do not add it.</strong>
</td>
</tr>
<tr>
<td class="label">Image (optional)</td>
<td>
<input type="text" id="image" name="image" size="60" value="<?=display_str($Torrent['Image']) ?>" <?=$this->Disabled?>/>
</td>
</tr>
<tr>
<td class="label">Album Description</td>
<td>
<textarea name="album_desc" id="album_desc" cols="60" rows="8" <?=$this->Disabled?>><?=display_str($Torrent['GroupDescription']); ?></textarea>
<p class="min_padding">Contains background information such as album history and maybe a review.</p>
</td>
</tr>
<? } // if new torrent ?>
<tr>
<td class="label">Release Description (optional)</td>
<td>
<textarea name="release_desc" id="release_desc" cols="60" rows="8"><?=display_str($Torrent['TorrentDescription']); ?></textarea>
<p class="min_padding">Contains information like encoder settings or details of the ripping process. <b>DO NOT PASTE THE RIPPING LOG HERE.</b></p>
</td>
</tr>
</table>
<?
}//function music_form
function audiobook_form() {
$Torrent = $this->Torrent;
?>
<table cellpadding="3" cellspacing="1" border="0" class="border slice" width="100%">
<? if($this->NewTorrent){ ?>
<tr id="title_tr">
<td class="label">Artist - Title</td>
<td>
<input type="text" id="title" name="title" size="60" value="<?=display_str($Torrent['Title']) ?>" />
<p class="min_padding">Should only include the artist if applicable</p>
</td>
</tr>
<? } ?>
<tr id="year_tr">
<td class="label">Year</td>
<td>
<input type="text" id="year" name="year" size="5" value="<?=display_str($Torrent['Year']) ?>" />
</td>
</tr>
<tr>
<td class="label">Format</td>
<td>
<select name="format" onchange="Format()">
<option value="">---</option>
<?
foreach(display_array($this->Formats) as $Format) {
echo "<option value='$Format'";
if($Format == $Torrent['Format']) { echo " selected='selected'"; }
echo ">";
echo $Format;
echo "</option>\n";
}
?>
</select>
</td>
</tr>
<tr>
<td class="label">Bitrate</td>
<td>
<select id="bitrate" name="bitrate" onchange="Bitrate()">
<option value="">---</option>
<? if($Torrent['Bitrate'] && !in_array($Torrent['Bitrate'], $this->Bitrates)) {
$OtherBitrate = true;
} else {
$OtherBitrate = false;
}
foreach(display_array($this->Bitrates) as $Bitrate) {
echo "<option value='$Bitrate'";
if($Bitrate == $Torrent['Bitrate']) {
echo " selected='selected'";
}
echo ">";
echo $Bitrate;
echo "</option>\n";
}
?>
</select>
<span id="other_bitrate_span"<? if(!$OtherBitrate) { echo ' class="hidden"'; } ?> >
<input type="text" name="other_bitrate" size="5" id="other_bitrate"<? if($OtherBitrate) { echo " value='".display_str($Torrent['Encoding'])."'";} ?> onchange="AltBitrate()" />
<? if($this->NewTorrent) { ?>
<input type="checkbox" id="vbr" name="vbr" /> (VBR)
<? } ?>
</span>
</td>
</tr>
<? if($this->NewTorrent) { ?>
<tr>
<td class="label">Tags</td>
<td>
<input type="text" id="tags" name="tags" size="60" value="<?=display_str($Torrent['TagList']) ?>" />
</td>
</tr>
<tr>
<td class="label">Description</td>
<td>
<textarea name="album_desc" id="album_desc" cols="60" rows="8"><?=display_str($Torrent['GroupDescription']); ?></textarea>
<p class="min_padding">Contains information like the track listing, and maybe a review.</p>
</td>
</tr>
<? }?>
<tr>
<td class="label">Release Description (optional)</td>
<td>
<textarea name="release_desc" id="release_desc" cols="60" rows="8"><?=display_str($Torrent['TorrentDescription']); ?></textarea>
<p class="min_padding">Contains information like encoder settings, and/or a log of the ripping process.</p>
</td>
</tr>
</table>
<?
}//function audiobook_form
function simple_form($CategoryID) {
$Torrent = $this->Torrent;
?> <table cellpadding="3" cellspacing="1" border="0" class="border slice" width="100%">
<tr id="name">
<? if ($this->NewTorrent) {
if ($this->Categories[$CategoryID] == 'E-Books') { ?>
<td class="label">Author - Title</td>
<? } else { ?>
<td class="label">Title</td>
<? }
?>
<td>
<input type="text" id="title" name="title" size="60" value="<?=display_str($Torrent['Title']) ?>" />
</td>
</tr>
<tr>
<td class="label">Tags</td>
<td>
<input type="text" id="tags" name="tags" size="60" value="<?=display_str($Torrent['TagList']) ?>" />
</td>
</tr>
<tr>
<td class="label">Description</td>
<td>
<textarea name="desc" id="desc" cols="60" rows="8"><?=display_str($Torrent['GroupDescription']); ?></textarea>
</td>
</tr>
<? } ?>
</table>
<? }//function simple_form
}//class
?>

107
classes/class_user_rank.php Normal file
View File

@ -0,0 +1,107 @@
<?
define('PREFIX', 'percentiles_'); // Prefix for memcache keys, to make life easier
class USER_RANK {
// Returns a 101 row array (101 percentiles - 0 - 100), with the minimum value for that percentile as the value for each row
// BTW - ingenious
function build_table($MemKey, $Query) {
global $Cache,$DB;
$DB->query("DROP TEMPORARY TABLE IF EXISTS stats");
$DB->query("CREATE TEMPORARY TABLE stats
(ID int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
Val bigint(20) NOT NULL);");
$DB->query("INSERT INTO stats (Val) ".$Query);
$DB->query("SELECT COUNT(ID) FROM stats");
list($UserCount) = $DB->next_record();
$DB->query("SELECT MIN(Val) FROM stats GROUP BY CEIL(ID/(".(int)$UserCount."/100));");
$Table = $DB->to_array();
// Give a little variation to the cache length, so all the tables don't expire at the same time
$Cache->cache_value($MemKey, $Table, 3600*24*rand(800,1000)*0.001);
return $Table;
}
function table_query($TableName) {
switch($TableName) {
case 'uploaded':
$Query = "SELECT Uploaded FROM users_main WHERE Enabled='1' AND Uploaded>0 ORDER BY Uploaded;";
break;
case 'downloaded':
$Query = "SELECT Downloaded FROM users_main WHERE Enabled='1' AND Downloaded>0 ORDER BY Downloaded;";
break;
case 'uploads':
$Query = "SELECT COUNT(t.ID) AS Uploads FROM users_main AS um JOIN torrents AS t ON t.UserID=um.ID WHERE um.Enabled='1' GROUP BY um.ID ORDER BY Uploads;";
break;
case 'requests':
$Query = "SELECT COUNT(r.ID) AS Requests FROM users_main AS um JOIN requests AS r ON r.FillerID=um.ID WHERE um.Enabled='1' GROUP BY um.ID ORDER BY Requests;";
break;
case 'posts':
$Query = "SELECT COUNT(p.ID) AS Posts FROM users_main AS um JOIN forums_posts AS p ON p.AuthorID=um.ID WHERE um.Enabled='1' GROUP BY um.ID ORDER BY Posts;";
break;
case 'bounty':
//Request bunny exception
$Query = "SELECT SUM(rv.Bounty) AS Bounty FROM users_main AS um JOIN requests_votes AS rv ON rv.UserID=um.ID WHERE um.Enabled='1' AND um.ID <> 260542 GROUP BY um.ID ORDER BY Bounty;";
break;
case 'artists':
$Query = "SELECT COUNT(ta.ArtistID) AS Artists FROM torrents_artists AS ta JOIN torrents_group AS tg ON tg.ID=ta.GroupID JOIN torrents AS t ON t.GroupID = tg.ID WHERE t.UserID != ta.UserID GROUP BY tg.ID ORDER BY Artists ASC";
break;
}
return $Query;
}
function get_rank($TableName, $Value) {
if($Value == 0) { return 0; }
global $Cache, $DB;
$Table = $Cache->get_value(PREFIX.$TableName);
if(!$Table) {
//Cache lock!
$Lock = $Cache->get_value(PREFIX.$TableName."_lock");
if($Lock) {
?><script type="script/javascript">setTimeout('window.location="http://<?=NONSSL_SITE_URL?><?=$_SERVER['REQUEST_URI']?>"', 5)</script><?
} else {
$Cache->cache_value(PREFIX.$TableName."_lock", '1', 10);
$Table = $this->build_table(PREFIX.$TableName, $this->table_query($TableName));
}
}
$LastPercentile = 0;
foreach ($Table as $Row) {
list($CurValue) = $Row;
if($CurValue>=$Value) {
return $LastPercentile;
}
$LastPercentile++;
}
return 100; // 100th percentile
}
function overall_score($Uploaded, $Downloaded, $Uploads, $Requests, $Posts, $Bounty, $Artists, $Ratio){
// We can do this all in 1 line, but it's easier to read this way
if($Ratio>1) { $Ratio = 1; }
$TotalScore = 0;
$TotalScore += $Uploaded*15;
$TotalScore += $Downloaded*8;
$TotalScore += $Uploads*25;
$TotalScore += $Requests*2;
$TotalScore += $Posts;
$TotalScore += $Bounty;
$TotalScore += $Artists;
$TotalScore /= (15+8+25+2+1+1+1);
$TotalScore *= $Ratio;
return $TotalScore;
}
}
?>

151
classes/class_useragent.php Normal file
View File

@ -0,0 +1,151 @@
<?
class USER_AGENT {
var $Browsers = array(
//Less popular
'Shiira' => 'Shiira',
'Songbird' => 'Songbird',
'SeaMonkey' => 'SeaMonkey',
'OmniWeb' => 'OmniWeb',
'Camino' => 'Camino',
'Chimera' => 'Chimera',
'Epiphany' => 'Epiphany',
'Konqueror' => 'Konqueror',
'Iceweasel' => 'Iceweasel',
'Lynx' => 'Lynx',
'Links' => 'Links',
'libcurl' => 'cURL',
'midori' => 'Midori',
'Blackberry' => 'Blackberry Browser',
//Big names
'Firefox' => 'Firefox',
'Chrome' => 'Chrome',
'Safari' => 'Safari',
'Opera' => 'Opera',
//Put chrome frame above IE
'chromeframe' => 'Chrome Frame',
'x-clock' => 'Chrome Frame',
'MSIE' => 'Internet Explorer',
//Firefox versions
'Shiretoko' => 'Firefox (Experimental)',
'Minefield' => 'Firefox (Experimental)',
'GranParadiso' => 'Firefox (Experimental)',
'Namoroka' => 'Firefox (Experimental)',
'AppleWebKit' => 'WebKit',
'Mozilla' => 'Mozilla'
//Weird shit
/*
'WWW-Mechanize' => 'Perl',
'Wget' => 'Wget',
'BTWebClient' => 'µTorrent',
'Transmission' => 'Transmission',
'Java' => 'Java',
'RSS' => 'RSS Downloader'
*/
);
var $OperatingSystems = array(
//Mobile
'SymbianOS' => 'Symbian',
'blackberry' => 'BlackBerry',
'iphone' => 'iPhone',
'ipod' => 'iPhone',
'android' => 'Android',
'palm' => 'Palm',
'mot-razr' => 'Motorola Razr',
//Windows
'Windows NT 6.1' => 'Windows 7',
'Windows 7' => 'Windows 7',
'Windows NT 6.0' => 'Windows Vista',
'Windows Vista' => 'Windows Vista',
'windows nt 5.2' => 'Windows 2003',
'windows 2003' => 'Windows 2003',
'windows nt 5.0' => 'Windows 2000',
'windows 2000' => 'Windows 2000',
'windows nt 5.1' => 'Windows XP',
'windows xp' => 'Windows XP',
'Win 9x 4.90' => 'Windows ME',
'Windows Me' => 'Windows ME',
'windows nt' => 'Windows NT',
'winnt' => 'Windows NT',
'windows 98' => 'Windows 98',
'windows ce' => 'Windows CE',
'win98' => 'Windows 98',
'windows 95' => 'Windows 95',
'windows 95' => 'Windows 95',
'win95' => 'Windows 95',
'win16' => 'Windows 3.1',
//'windows' => 'Windows',
//OS X
'os x' => 'Mac OS X',
'macintosh' => 'Mac OS X',
'darwin' => 'Mac OS X',
//Less popular
'ubuntu' => 'Ubuntu',
'debian' => 'Debian',
'fedora' => 'Fedora',
'freebsd' => 'FreeBSD',
'openbsd' => 'OpenBSD',
'bsd' => 'BSD',
'x11' => 'Linux',
'gnu' => 'Linux',
'linux' => 'Linux',
'unix' => 'Unix',
'Sun OS' => 'Sun',
'Sun' => 'Sun',
//Weird shit
/*
'WWW-Mechanize' => 'Perl',
'Wget' => 'Wget',
'BTWebClient' => 'µTorrent',
'Transmission' => 'Transmission',
'Java' => 'Java',
'RSS' => 'RSS Downloader',
*/
//Catch-all
'win' => 'Windows',
'mac' => 'Mac OS X'
);
public function operating_system(&$UserAgentString) {
if (empty($UserAgentString)) {
return 'Hidden';
}
$Return = 'Unknown';
foreach ($this->OperatingSystems as $String => $OperatingSystem) {
if (stripos($UserAgentString, $String) !== false) {
$Return = $OperatingSystem;
break;
}
}
return $Return;
}
public function mobile(&$UserAgentString) {
if (strpos($UserAgentString, 'iPad')) {
return false;
}
//Mobi catches Mobile
if (/*strpos($UserAgentString, 'Mobile') || */strpos($UserAgentString, 'Device') || strpos($UserAgentString, 'Mobi') || strpos($UserAgentString, 'Mini') || strpos($UserAgentString, 'webOS')) {
return true;
}
return false;
}
public function browser(&$UserAgentString) {
if (empty($UserAgentString)) {
return 'Hidden';
}
$Return = 'Unknown';
foreach ($this->Browsers as $String => $Browser) {
if (strpos($UserAgentString, $String) !== false) {
$Return = $Browser;
break;
}
}
if($this->mobile($UserAgentString)) {
$Return .= ' Mobile';
}
return $Return;
}
}

187
classes/class_validate.php Normal file
View File

@ -0,0 +1,187 @@
<?
/*-- TODO ---------------------------//
Writeup how to use the VALIDATE class, add in support for form id checks
Complete the number and date validation
Finish the GenerateJS stuff
//-----------------------------------*/
class VALIDATE {
var $Fields=array();
function SetFields($FieldName,$Required,$FieldType,$ErrorMessage,$Options=array()) {
$this->Fields[$FieldName]['Type']=strtolower($FieldType);
$this->Fields[$FieldName]['Required']=$Required;
$this->Fields[$FieldName]['ErrorMessage']=$ErrorMessage;
if(!empty($Options['maxlength'])) {
$this->Fields[$FieldName]['MaxLength']=$Options['maxlength'];
}
if(!empty($Options['minlength'])) {
$this->Fields[$FieldName]['MinLength']=$Options['minlength'];
}
if(!empty($Options['comparefield'])) {
$this->Fields[$FieldName]['CompareField']=$Options['comparefield'];
}
if(!empty($Options['allowperiod'])) {
$this->Fields[$FieldName]['AllowPeriod']=$Options['allowperiod'];
}
if(!empty($Options['allowcomma'])) {
$this->Fields[$FieldName]['AllowComma']=$Options['allowcomma'];
}
if(!empty($Options['inarray'])) {
$this->Fields[$FieldName]['InArray']=$Options['inarray'];
}
if(!empty($Options['regex'])) {
$this->Fields[$FieldName]['Regex']=$Options['regex'];
}
}
function ValidateForm($ValidateArray) {
reset($this->Fields);
foreach ($this->Fields as $FieldKey => $Field) {
$ValidateVar=$ValidateArray[$FieldKey];
if($ValidateVar!="" || !empty($Field['Required']) || $Field['Type']=="date") {
if($Field['Type']=="string") {
if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=255; }
if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=1; }
if(strlen($ValidateVar)>$MaxLength) { return $Field['ErrorMessage']; }
elseif(strlen($ValidateVar)<$MinLength) { return $Field['ErrorMessage']; }
} elseif($Field['Type']=="number") {
if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=''; }
if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=0; }
$Match='0-9';
if(isset($Field['AllowPeriod'])) { $Match.='.'; }
if(isset($Field['AllowComma'])) { $Match.=','; }
if(preg_match('/[^'.$Match.']/', $ValidateVar) || strlen($ValidateVar)<1) { return $Field['ErrorMessage']; }
elseif($MaxLength!="" && $ValidateVar>$MaxLength) { return $Field['ErrorMessage']."!!"; }
elseif($ValidateVar<$MinLength) { return $Field['ErrorMessage']."$MinLength"; }
} elseif($Field['Type']=="email") {
if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=255; }
if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=6; }
if(!preg_match("/^".EMAIL_REGEX."$/i", $ValidateVar)) { return $Field['ErrorMessage']; }
elseif(strlen($ValidateVar)>$MaxLength) { return $Field['ErrorMessage']; }
elseif(strlen($ValidateVar)<$MinLength) { return $Field['ErrorMessage']; }
} elseif($Field['Type']=="link") {
if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=255; }
if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=10; }
if(!preg_match('/^(https?):\/\/([a-z0-9\-\_]+\.)+([a-z]{1,5}[^\.])(\/[^<>]+)*$/i', $ValidateVar)) { return $Field['ErrorMessage']; }
elseif(strlen($ValidateVar)>$MaxLength) { return $Field['ErrorMessage']; }
elseif(strlen($ValidateVar)<$MinLength) { return $Field['ErrorMessage']; }
} elseif($Field['Type']=="username") {
if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=20; }
if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=1; }
if(preg_match('/[^a-z0-9_\-?]/i', $ValidateVar)) { return $Field['ErrorMessage']; }
elseif(strlen($ValidateVar)>$MaxLength) { return $Field['ErrorMessage']; }
elseif(strlen($ValidateVar)<$MinLength) { return $Field['ErrorMessage']; }
} elseif($Field['Type']=="checkbox") {
if(!isset($ValidateArray[$FieldKey])) { return $Field['ErrorMessage']; }
} elseif($Field['Type']=="compare") {
if($ValidateArray[$Field['CompareField']]!=$ValidateVar) { return $Field['ErrorMessage']; }
} elseif($Field['Type']=="inarray") {
if(array_search($ValidateVar, $Field['InArray'])===false) { return $Field['ErrorMessage']; }
} elseif($Field['Type']=="regex") {
if(!preg_match($Field['Regex'], $ValidateVar)) { return $Field['ErrorMessage']; }
}
}
} // while
} // function
function GenerateJS($FormID) {
$ReturnJS="<script type=\"text/javascript\" language=\"javascript\">\r\n";
$ReturnJS.="//<![CDATA[\r\n";
$ReturnJS.="function formVal() {\r\n";
$ReturnJS.=" clearErrors('".$FormID."');\r\n";
reset($this->Fields);
foreach ($this->Fields as $FieldKey => $Field) {
if($Field['Type']=="string") {
$ValItem=' if($(\'#'.$FieldKey.'\').raw().value==""';
if(!empty($Field['MaxLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length>'.$Field['MaxLength']; } else { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length>255'; }
if(!empty($Field['MinLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length<'.$Field['MinLength']; }
$ValItem.=') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
} elseif($Field['Type']=="number") {
$Match='0-9';
if(!empty($Field['AllowPeriod'])) { $Match.='.'; }
if(!empty($Field['AllowComma'])) { $Match.=','; }
$ValItem=' if($(\'#'.$FieldKey.'\').raw().value.match(/[^'.$Match.']/) || $(\'#'.$FieldKey.'\').raw().value.length<1';
if(!empty($Field['MaxLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value/1>'.$Field['MaxLength']; }
if(!empty($Field['MinLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value/1<'.$Field['MinLength']; }
$ValItem.=') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
} elseif($Field['Type']=="email") {
$ValItem=' if(!validEmail($(\'#'.$FieldKey.'\').raw().value)';
if(!empty($Field['MaxLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length>'.$Field['MaxLength']; } else { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length>255'; }
if(!empty($Field['MinLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length<'.$Field['MinLength']; } else { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length<6'; }
$ValItem.=') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
} elseif($Field['Type']=="link") {
$ValItem=' if(!validLink($(\'#'.$FieldKey.'\').raw().value)';
if(!empty($Field['MaxLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length>'.$Field['MaxLength']; } else { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length>255'; }
if(!empty($Field['MinLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length<'.$Field['MinLength']; } else { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length<10'; }
$ValItem.=') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
} elseif($Field['Type']=="username") {
$ValItem=' if($(\'#'.$FieldKey.'\').raw().value.match(/[^a-zA-Z0-9_\-]/)';
if(!empty($Field['MaxLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length>'.$Field['MaxLength']; }
if(!empty($Field['MinLength'])) { $ValItem.=' || $(\'#'.$FieldKey.'\').raw().value.length<'.$Field['MinLength']; }
$ValItem.=') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
} elseif($Field['Type']=="regex") {
$ValItem=' if(!$(\'#'.$FieldKey.'\').raw().value.match('.$Field['Regex'].')) { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
} elseif($Field['Type']=="date") {
$DisplayError=$FieldKey."month";
if(isset($Field['MinLength']) && $Field['MinLength']==3) { $Day='$(\'#'.$FieldKey.'day\').raw().value'; $DisplayError.=",".$FieldKey."day"; } else { $Day="1"; }
$DisplayError.=",".$FieldKey."year";
$ValItemHold=' if(!validDate($(\'#'.$FieldKey.'month\').raw().value+\'/\'+'.$Day.'+\'/\'+$(\'#'.$FieldKey.'year\').raw().value)) { return showError(\''.$DisplayError.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
if(empty($Field['Required'])) {
$ValItem=' if($(\'#'.$FieldKey.'month\').raw().value!=""';
if(isset($Field['MinLength']) && $Field['MinLength']==3) { $ValItem.=' || $(\'#'.$FieldKey.'day\').raw().value!=""'; }
$ValItem.=' || $(\'#'.$FieldKey.'year\').raw().value!="") {'."\r\n";
$ValItem.=$ValItemHold;
$ValItem.=" }\r\n";
} else {
$ValItem.=$ValItemHold;
}
} elseif($Field['Type']=="checkbox") {
$ValItem=' if(!$(\'#'.$FieldKey.'\').checked) { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
} elseif($Field['Type']=="compare") {
$ValItem=' if($(\'#'.$FieldKey.'\').raw().value!=$(\'#'.$Field['CompareField'].'\').raw().value) { return showError(\''.$FieldKey.','.$Field['CompareField'].'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
}
if(empty($Field['Required']) && $Field['Type']!="date") {
$ReturnJS.=' if($(\'#'.$FieldKey.'\').raw().value!="") {'."\r\n ";
$ReturnJS.=$ValItem;
$ReturnJS.=" }\r\n";
} else {
$ReturnJS.=$ValItem;
}
$ValItem='';
}
$ReturnJS.="}\r\n";
$ReturnJS.="//]]>\r\n";
$ReturnJS.="</script>\r\n";
return $ReturnJS;
}
}
?>

86
classes/class_wiki.php Normal file
View File

@ -0,0 +1,86 @@
<?
/*########################################################################
## Wiki class ##
##########################################################################
Seeing as each page has to manage its wiki separately (for performance
reasons - JOINs instead of multiple queries), this class is rather bare.
The only useful function in here is revision_history(). It creates a
table with the revision history for that particular wiki page.
class_wiki depends on your wiki table being structured like this:
+------------+---------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------------------+-------+
| RevisionID | int(12) | NO | PRI | 0 | |
| PageID | int(10) | NO | MUL | 0 | |
| Body | text | YES | | NULL | |
| UserID | int(10) | NO | MUL | 0 | |
| Summary | varchar(100) | YES | | NULL | |
| Time | datetime | NO | MUL | 0000-00-00 00:00:00 | |
+------------+---------------+------+-----+---------------------+-------+
It is also recommended that you have a field in the main table for
whatever the page is (eg. details.php main table = torrents), so you can
do a JOIN.
########################################################################*/
class WIKI {
var $Table = '';
var $PageID = 0;
var $BaseURL = '';
function WIKI($Table, $PageID, $BaseURL = ''){
$this->Table = $Table;
$this->PageID = $PageID;
$this->BaseURL = $BaseURL;
}
function revision_history(){
global $DB;
$BaseURL = $this->BaseURL;
$DB->query("SELECT
RevisionID,
Summary,
Time,
UserID,
users.Username
FROM ".$this->Table." AS wiki
JOIN users_main AS users ON users.ID = wiki.UserID
WHERE wiki.PageID = ".$this->PageID."
ORDER BY RevisionID DESC");
//----------------------------------------------- ?>
<table cellpadding='6' cellspacing='1' border='0' width='100%' class='border'>
<tr class="colhead">
<td>Revision</td>
<td>Summary</td>
</tr>
<? //-----------------------------------------
$Row = 'a';
while(list($RevisionID, $Summary, $Time, $UserID, $Username) = $DB->next_record()){
$Row = ($Row == 'a') ? 'b' : 'a';
//------------------------------------------------------ ?>
<tr class="row<?=$Row?>">
<td>
<?= "<a href='$BaseURL&amp;revisionid=$RevisionID'>#$RevisionID</a>" ?>
</td>
<td>
<strong>Edited by</strong> <a href="user.php?id=<?=$UserID?>"><?=$Username ?></a>
<strong>Reason:</strong> <?=$Summary?>
</td>
</tr>
<? //---------------------------------------------------
}
//-------------------------------------------- ?>
</table>
<?
}
} // class
?>

184
classes/class_zip.php Normal file
View File

@ -0,0 +1,184 @@
<?
/*************************************************************************|
|--------------- Zip class -----------------------------------------------|
|*************************************************************************|
This class provides a convenient way for us to generate and serve zip
archives to our end users, both from physical files, cached
or already parsed data (torrent files). It's all done on the fly, due to
the high probability that a filesystem stored archive will never be
downloaded twice.
Utilizes gzcompress, based upon RFC 1950
//------------- How it works --------------//
Basic concept is construct archive, add files, and serve on the fly.
//------------- How to use it --------------//
* First, construct the archive:
$Zip = new ZIP('FileName');
Adds the headers so that add_file can stream and we don't need to create a massive buffer.
open_stream(); was integrated into the constructor to conform with Object-Oriented Standards.
$Zip->unlimit();
A simple shortcut function for raising the basic PHP limits, time and memory for larger archives.
-----
* Then, add files and begin streaming to the user to avoid memory buffering:
$Zip->add_file(file_get_contents("data/file.txt"), "File.txt");
Adds the contents of data/file.txt into File.txt in the archive root.
$Zip->add_file($TorrentData, "Bookmarks/Artist - Album [2008].torrent");
Adds the parsed torrent to the archive in the Bookmarks folder (created simply by placing it in the path).
-----
* Then, close the archive to the user:
$Zip->close_stream();
This collects everything put together thus far in the archive, and streams it to the user in the form of Test7.zip
//------ Explanation of basic functions ------//
add_file(Contents, Internal Path)
Adds the contents to the archive, where it will be extracted to Internal Path.
close_stream();
Collect and stream to the user.
//------------- Detailed example -------------//
require('classes/class_zip.php');
$Zip = new ZIP('FileName');
$Name = 'Ubuntu-8.10';
$Zip->add_file($TorrentData, 'Torrents/'.file_string($Name).'.torrent');
$Zip->add_file(file_get_contents('zip.php'), 'zip.php');
$Zip->close_stream();
//---------- Development reference -----------//
http://www.pkware.com/documents/casestudies/APPNOTE.TXT - ZIP spec (this class)
http://www.ietf.org/rfc/rfc1950.txt - ZLIB compression spec (gzcompress function)
http://www.fileformat.info/tool/hexdump.htm - Useful for analyzing ZIP files
|*************************************************************************/
if (!extension_loaded('zlib')) {
error('Zlib Extension not loaded.');
}
/*
//Handles timestamps
function dostime($TimeStamp = 0) {
if(!is_number($TimeStamp)) { // Assume that $TimeStamp is SQL timestamp
if($TimeStamp == '0000-00-00 00:00:00') { return 'Never'; }
$TimeStamp = strtotime($TimeStamp);
}
$Date = ($TimeStamp == 0) ? getdate() : getdate($TimeStamp);
$Hex = dechex((($Date['year'] - 1980) << 25) | ($Date['mon'] << 21) | ($Date['mday'] << 16) | ($Date['hours'] << 11) | ($Date['minutes'] << 5) | ($Date['seconds'] >> 1));
eval("\$Return = \"\x$Hex[6]$Hex[7]\x$Hex[4]$Hex[5]\x$Hex[2]$Hex[3]\x$Hex[0]$Hex[1]\";");
return $Return;
}
*/
class ZIP {
public $ArchiveSize = 0; //Total size
public $ArchiveFiles = 0; // Total files
private $Structure = ''; // Structure saved to memory
private $FileOffset = 0; // Offset to write data
private $Data = ''; //An idea
public function __construct ($ArchiveName='Archive') {
header("Content-type: application/octet-stream"); //Stream download
header("Content-disposition: attachment; filename=\"".urlencode($ArchiveName).".zip\""); //Name the archive
}
public static function unlimit () {
ob_end_clean();
set_time_limit(3600); //Limit 1 hour
ini_set('memory_limit', '1024M'); // Because the buffers can get extremely large
}
public function add_file ($FileData, $ArchivePath, $TimeStamp = 0) {
/* File header */
$this->Data = "\x50\x4b\x03\x04"; // PK signature
$this->Data .= "\x14\x00"; // Version requirements
$this->Data .= "\x00\x00"; // Bit flag
$this->Data .= "\x08\x00"; // Compression
//$this->Data .= dostime($TimeStamp); //Last modified
$this->Data .= "\x00\x00\x00\x00";
$DataLength = strlen($FileData); // Saved as varibale to avoid wasting CPU calculating it multiple times.
$CRC32 = crc32($FileData); // Ditto.
$ZipData = gzcompress($FileData); // Ditto.
$ZipData = substr ($ZipData, 2,(strlen($ZipData) - 6)); // Checksum resolution
$ZipLength = strlen($ZipData); //Ditto.
$this->Data .= pack("V",$CRC32); // CRC-32
$this->Data .= pack("V",$ZipLength); // Compressed filesize
$this->Data .= pack("V",$DataLength); // Uncompressed filesize
$this->Data .= pack("v",strlen($ArchivePath)); // Pathname length
$this->Data .="\x00\x00"; // Extra field length (0'd so we can ignore this)
$this->Data .= $ArchivePath; // Filename & Exta Field (length set to 0 so ignored)
/* END file header */
/* File data */
$this->Data .= $ZipData; // File data
/* END file data */
/* Data descriptor
Not needed (only needed when 3rd bitflag is set), causes problems with OS X archive utility
$this->Data .= pack("V",$CRC32); // CRC-32
$this->Data .= pack("V",$ZipLength); // Compressed filesize
$this->Data .= pack("V",$DataLength); // Uncompressed filesize
END data descriptor */
$FileDataLength = strlen($this->Data);
$this->ArchiveSize = $this->ArchiveSize + $FileDataLength; // All we really need is the size
$CurrentOffset = $this->ArchiveSize; // Update offsets
echo $this->Data; // Get this out to reduce our memory consumption
/* Central Directory Structure */
$CDS = "\x50\x4b\x01\x02"; // CDS signature
$CDS .="\x00\x00"; // Constructor version
$CDS .="\x14\x00"; // Version requirements
$CDS .="\x00\x00"; // Bit flag
$CDS .="\x08\x00"; // Compression
$CDS .="\x00\x00\x00\x00"; // Last modified
$CDS .= pack("V",$CRC32); // CRC-32
$CDS .= pack("V",$ZipLength); // Compressed filesize
$CDS .= pack("V",$DataLength); // Uncompressed filesize
$CDS .= pack("v",strlen($ArchivePath)); // Pathname length
$CDS .="\x00\x00"; // Extra field length (0'd so we can ignore this)
$CDS .="\x00\x00"; // File comment length (no comment, 0'd)
$CDS .="\x00\x00"; // Disk number start (0 seems valid)
$CDS .="\x00\x00"; // Internal file attributes (again with the 0's)
$CDS .="\x20\x00\x00\x00"; // External file attributes
$CDS .= pack("V", $this->FileOffset ); // Offsets
$CDS .= $ArchivePath; // Filename & Exta Field (length set to 0 so ignored)
/* END central Directory Structure */
$this->FileOffset = $CurrentOffset; // Update offsets
$this->Structure .= $CDS; // Append to structure
$this->ArchiveFiles++; // Increment file count
}
public function close_stream() {
echo $this->Structure; // Structure Root
echo "\x50\x4b\x05\x06"; // End of central directory signature
echo "\x00\x00"; // This disk
echo "\x00\x00"; // CDS start
echo pack("v", $this->ArchiveFiles); // Handle the numebr of entries
echo pack("v", $this->ArchiveFiles); // Ditto
echo pack("V", strlen($this->Structure)); //Size
echo pack("V", $this->ArchiveSize); // Offset
echo "\x00\x00"; // No comment, close it off
}
}

182
classes/config.template Normal file
View File

@ -0,0 +1,182 @@
<?php
date_default_timezone_set('UTC');
// Main settings
define('SITE_NAME', ''); //The name of your site
define('NONSSL_SITE_URL', ''); //The FQDN of your site
define('SSL_SITE_URL', ''); //The FQDN of your site, make this different if you are using a subdomain for ssl
define('SERVER_ROOT', '/path'); //The root of the server, used for includes, purpose is to shorten the path string
define('ANNOUNCE_URL', 'http://'.NONSSL_SITE_URL.':2710'); //Announce URL
// Allows you to run static content off another server. Default is usually what you want.
define('NONSSL_STATIC_SERVER', 'static/');
define('SSL_STATIC_SERVER', 'static/');
// Keys
define('ENCKEY', ''); //Random key. The key for encryption
define('SITE_SALT', ''); //Random key. Default site wide salt for passwords, DO NOT LEAVE THIS BLANK/CHANGE AFTER LAUNCH!
define('SCHEDULE_KEY', ''); // Random key. This key must be the argument to schedule.php for the schedule to work.
define('RSS_HASH', ''); //Random key. Used for generating unique RSS auth key.
// MySQL details
define('SQLHOST', 'localhost'); //The MySQL host ip/fqdn
define('SQLLOGIN', '');//The MySQL login
define('SQLPASS', ''); //The MySQL password
define('SQLDB', 'gazelle'); //The MySQL database to use
define('SQLPORT', 3306); //The MySQL port to connect on
define('SQLSOCK', '/var/run/mysqld/mysql.sock');
// Memcached details
define('MEMCACHED_HOST', 'unix:///var/run/memcached.sock'); // unix sockets are fast, and other people can't telnet into them
define('MEMCACHED_PORT', 0);
// Sphinx details
define('SPHINX_HOST', 'localhost');
define('SPHINX_PORT', 9312);
define('SPHINX_MAX_MATCHES', 1000); // Must be <= the server's max_matches variable (default 1000)
define('SPHINX_MATCHES_START', 100); // Number of matches to load on first page
define('SPHINX_MATCHES_STEP', 50); // Load more torrents every SPHINX_MATCHES_STEP/TORRENTS_PER_PAGE page (Should be lower than SPHINX_MATCHES_START)
define('SPHINX_INDEX', 'torrents');
// Ocelot details
define('TRACKER_HOST', 'localhost');
define('TRACKER_PORT', 2710);
define('TRACKER_SECRET', ''); // Must be 32 characters and match site_password in Ocelot's config.cpp
if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 80) {
define('SITE_URL', NONSSL_SITE_URL);
define('STATIC_SERVER', NONSSL_STATIC_SERVER);
} else {
define('SITE_URL', SSL_SITE_URL);
define('STATIC_SERVER', SSL_STATIC_SERVER);
}
// Site settings
define('DEBUG_MODE', false); //Set to false if you dont want everyone to see debug information, can be overriden with 'site_debug'
define('OPEN_REGISTRATION', true); //Set to false to disable open regirstration, true to allow anyone to register
define('USER_LIMIT', 5000); //The maximum number of users the site can have, 0 for no limit
define('STARTING_INVITES', 0); //# of invites to give to newly registered users
define('DONOR_INVITES', 2);
// User class IDs needed for automatic promotions. Found in the 'permissions' table
// Name of class Class ID (NOT level)
define('USER', '2');
define('MEMBER', '3');
define('POWER', '4');
define('ARTIST', '19');
define('DONOR', '20');
define('ELITE', '5');
define('VIP', '6');
define('TORRENT_MASTER','7');
define('LEGEND', '8');
define('CELEB', '9');
define('MOD', '11');
define('DESIGNER', '13');
define('CODER', '14');
define('ADMIN', '1');
define('SYSOP', '15');
//Pagination
define('TORRENT_COMMENTS_PER_PAGE', 10);
define('POSTS_PER_PAGE', 25);
define('TOPICS_PER_PAGE', 50);
define('TORRENTS_PER_PAGE', 50);
define('REQUESTS_PER_PAGE', 25);
define('MESSAGES_PER_PAGE', 25);
define('LOG_ENTRIES_PER_PAGE', 50);
//Cache catalogues
define('THREAD_CATALOGUE', 500); // Limit to THREAD_CATALOGUE posts per cache key.
// IRC settings
define('BOT_NICK', '');
define('BOT_SERVER', ''); // IRC server address. Used for onsite chat tool.
define('BOT_PORT', 6667);
define('BOT_CHAN', '#'.NONSSL_SITE_URL);
define('BOT_ANNOUNCE_CHAN', '#');
define('BOT_STAFF_CHAN', '#');
define('BOT_DISABLED_CHAN', '#'); // Channel to refer disabled users to.
define('BOT_HELP_CHAN', '#');
define('BOT_DEBUG_CHAN', '#');
define('BOT_REPORT_CHAN', '#');
define('BOT_NICKSERV_PASS', '');
define('SOCKET_LISTEN_PORT', 51010);
define('SOCKET_LISTEN_ADDRESS', 'localhost');
define('ADMIN_CHAN', '#');
define('LAB_CHAN', '#');
define('STATUS_CHAN', '#');
// Miscellaneous values
$Categories = array('Music', 'Applications', 'E-Books', 'Audiobooks', 'E-Learning Videos', 'Comedy', 'Comics');
$CategoryIcons = array('music.png', 'apps.png', 'ebook.png', 'audiobook.png', 'elearning.png', 'comedy.png', 'comics.png');
$Formats = array('MP3', 'FLAC', 'Ogg Vorbis', 'AAC', 'AC3', 'DTS');
$Bitrates = array('192', 'APS (VBR)', 'V2 (VBR)', 'V1 (VBR)', '256', 'APX (VBR)', 'V0 (VBR)', 'q8.x (VBR)', '320', 'Lossless', '24bit Lossless', 'Other');
$Media = array('CD', 'DVD', 'Vinyl', 'Soundboard', 'SACD', 'DAT', 'Cassette', 'WEB');
$CollageCats = array(0=>'Personal', 1=>'Theme', 2=>'Genre introduction', 3=>'Discography', 4=>'Label', 5=>'Staff picks', 6=>'Charts');
$ReleaseTypes = array(1=>'Album', 3=>'Soundtrack', 5=>'EP', 6=>'Anthology', 7=>'Compilation', 9=>'Single', 11=>'Live album', 13=>'Remix', 14=>'Bootleg', 15=>'Interview', 16=>'Mixtape', 21=>'Unknown');
$ForumCats = array(1=>'Site', 5=>'Community', 10=>'Help', 8=>'Music', 20=>'Trash');
$ZIPGroups = array(
0 => 'MP3 (VBR) - High Quality',
1 => 'MP3 (VBR) - Low Quality',
2 => 'MP3 (CBR)',
3 => 'FLAC - Lossless',
4 => 'Others'
);
//3D array of attributes, OptionGroup, OptionNumber, Name
$ZIPOptions = array(
'00' => array(0,0,'V0'),
'01' => array(0,1,'APX'),
'02' => array(0,2,'256'),
'03' => array(0,3,'V1'),
'10' => array(1,0,'224'),
'11' => array(1,1,'V2'),
'12' => array(1,2,'APS'),
'13' => array(1,3,'192'),
'20' => array(2,0,'320'),
'21' => array(2,1,'256'),
'22' => array(2,2,'224'),
'23' => array(2,3,'192'),
'30' => array(3,0,'FLAC / 24bit / Vinyl'),
'31' => array(3,1,'FLAC / 24bit / DVD'),
'32' => array(3,2,'FLAC / 24bit / SACD'),
'33' => array(3,3,'FLAC / Log (100) / Cue'),
'34' => array(3,4,'FLAC / Log (100)'),
'35' => array(3,5,'FLAC / Log'),
'36' => array(3,6,'FLAC'),
'40' => array(4,0,'DTS'),
'41' => array(4,1,'Ogg Vorbis'),
'42' => array(4,2,'AAC - 320'),
'43' => array(4,3,'AAC - 256'),
'44' => array(4,4,'AAC - q5.5'),
'45' => array(4,5,'AAC - q5'),
'46' => array(4,6,'AAC - 192')
);
// Ratio requirements, in descending order
// Columns: Download amount, required ratio, grace period
$RatioRequirements = array(
array(50*1024*1024*1024, 0.60, date('Y-m-d H:i:s')),
array(40*1024*1024*1024, 0.50, date('Y-m-d H:i:s')),
array(30*1024*1024*1024, 0.40, date('Y-m-d H:i:s')),
array(20*1024*1024*1024, 0.30, date('Y-m-d H:i:s')),
array(10*1024*1024*1024, 0.20, date('Y-m-d H:i:s')),
array(5*1024*1024*1024, 0.15, date('Y-m-d H:i:s', time()-(60*60*24*14)))
);
//Captcha fonts should be located in /classes/fonts
$CaptchaFonts=array('ARIBLK.TTF','IMPACT.TTF','TREBUC.TTF','TREBUCBD.TTF','TREBUCBI.TTF','TREBUCIT.TTF','VERDANA.TTF','VERDANAB.TTF','VERDANAI.TTF','VERDANAZ.TTF');
//Captcha images should be located in /captcha
$CaptchaBGs=array('captcha1.png','captcha2.png','captcha3.png','captcha4.png','captcha5.png','captcha6.png','captcha7.png','captcha8.png','captcha9.png');
// Special characters, and what they should be converted to
// Used for torrent searching
$SpecialChars = array(
'&' => 'and'
);
?>

BIN
classes/fonts/ARIBLK.TTF Normal file

Binary file not shown.

BIN
classes/fonts/COMIC.TTF Normal file

Binary file not shown.

BIN
classes/fonts/COMICBD.TTF Normal file

Binary file not shown.

BIN
classes/fonts/GEORGIA.TTF Normal file

Binary file not shown.

BIN
classes/fonts/GEORGIAB.TTF Normal file

Binary file not shown.

BIN
classes/fonts/GEORGIAI.TTF Normal file

Binary file not shown.

BIN
classes/fonts/GEORGIAZ.TTF Normal file

Binary file not shown.

BIN
classes/fonts/IMPACT.TTF Normal file

Binary file not shown.

BIN
classes/fonts/MISTRAL.TTF Normal file

Binary file not shown.

107
classes/fonts/README.TXT Normal file
View File

@ -0,0 +1,107 @@
This document contains the End User Licensing Agreement, and instructions concerning font installation on the various Windows platforms.
Microsoft TrueType Fonts
END-USER LICENSE AGREEMENT FOR MICROSOFT SOFTWARE
---------------------------------------------------
IMPORTANT - READ CAREFULLY: This Microsoft End-User License Agreement ("EULA") is a legal agreement between you (either an individual or a single entity) and Microsoft Corporation for the Microsoft software accompanying this EULA, which includes computer software and may include associated media, printed materials, and "on-line" or electronic documentation ("SOFTWARE PRODUCT" or "SOFTWARE"). By exercising your rights to make and use copies of the SOFTWARE PRODUCT, you agree to be bound by the terms of this EULA. If you do not agree to the terms of this EULA, you may not use the SOFTWARE PRODUCT.
SOFTWARE PRODUCT LICENSE
The SOFTWARE PRODUCT is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. The SOFTWARE PRODUCT is licensed, not sold.
1. GRANT OF LICENSE. This EULA grants you the following rights:
· Installation and Use. You may install and use an unlimited number of copies of the SOFTWARE PRODUCT.
· Reproduction and Distribution. You may reproduce and distribute an unlimited number of copies of the SOFTWARE PRODUCT; provided that each copy shall be a true and complete copy, including all copyright and trademark notices, and shall be accompanied by a copy of this EULA. Copies of the SOFTWARE PRODUCT may not be distributed for profit either on a standalone basis or included as part of your own product.
2. DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS.
· Limitations on Reverse Engineering, Decompilation, and Disassembly. You may not reverse engineer, decompile, or disassemble the SOFTWARE PRODUCT, except and only to the extent that such activity is expressly permitted by applicable law notwithstanding this limitation.
· Restrictions on Alteration. You may not rename, edit or create any derivative works from the SOFTWARE PRODUCT, other than subsetting when embedding them in documents.
· Software Transfer. You may permanently transfer all of your rights under this EULA, provided the recipient agrees to the terms of this EULA.
· Termination. Without prejudice to any other rights, Microsoft may terminate this EULA if you fail to comply with the terms and conditions of this EULA. In such event, you must destroy all copies of the SOFTWARE PRODUCT and all of its component parts.
3. COPYRIGHT. All title and copyrights in and to the SOFTWARE PRODUCT (including but not limited to any images, text, and "applets" incorporated into the SOFTWARE PRODUCT), the accompanying printed materials, and any copies of the SOFTWARE PRODUCT are owned by Microsoft or its suppliers. The SOFTWARE PRODUCT is protected by copyright laws and international treaty provisions. Therefore, you must treat the SOFTWARE PRODUCT like any other copyrighted material.
4. U.S. GOVERNMENT RESTRICTED RIGHTS. The SOFTWARE PRODUCT and documentation are provided with RESTRICTED RIGHTS. Use, duplication, or disclosure by the Government is subject to restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and (2) of the Commercial Computer Software-Restricted Rights at 48 CFR 52.227-19, as applicable. Manufacturer is Microsoft Corporation/One Microsoft Way/Redmond, WA 98052-6399.
LIMITED WARRANTY
NO WARRANTIES. Microsoft expressly disclaims any warranty for the SOFTWARE PRODUCT. The SOFTWARE PRODUCT and any related documentation is provided "as is" without warranty of any kind, either express or implied, including, without limitation, the implied warranties or merchantability, fitness for a particular purpose, or noninfringement. The entire risk arising out of use or performance of the SOFTWARE PRODUCT remains with you.
NO LIABILITY FOR CONSEQUENTIAL DAMAGES. In no event shall Microsoft or its suppliers be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or any other pecuniary loss) arising out of the use of or inability to use this Microsoft product, even if Microsoft has been advised of the possibility of such damages. Because some states/jurisdictions do not allow the exclusion or limitation of liability for consequential or incidental damages, the above limitation may not apply to you.
MISCELLANEOUS
If you acquired this product in the United States, this EULA is governed by the laws of the State of Washington.
If this product was acquired outside the United States, then local laws may apply.
Should you have any questions concerning this EULA, or if you desire to contact Microsoft for any reason, please contact the Microsoft subsidiary serving your country, or write: Microsoft Sales Information Center/One Microsoft Way/Redmond, WA 98052-6399.
INSTALLING FONTS
________________
----------------
Windows95
---------
To add a new font to your computer:
1) Open the font folder from the Control Panel.
2) On the File menu, click Install New Font.
3) Click the drive and folder that contain the fonts you want to add.
4) Double-click the icon for the font you want to add.
Tips
To select more than one font to add, press and hold down the CTRL key, and then click the fonts you want.
To select a range of fonts in the list, press and hold down the SHIFT key while dragging the cursor over the fonts.
To add fonts from a network drive without using disk space on your computer, make sure Copy Fonts To Windows Folder is not checked.
Windows 3.1x
------------
To add fonts to your computer:
1) In the Control Panel window, choose the Fonts icon. The fonts already installed are listed in the Installed Fonts box.
2) Choose the Add button.
3) In the Add Fonts dialog box, select the font you want to add. You can add more than one font at a time. You can also select all the fonts listed by choosing the Select All button. If the font is not located in the current drive or directory, select the drive and directory where it is located. If the font you want to add is on someone else's computer, you can use the Network button to browse through and connect to shared directories on other computers.
4) If you are low on disk space and want to use the fonts directly from the directory (network or local) where they are located, without copying the font files to the Windows directory, clear the Copy Fonts To Windows Directory check box.
5) Choose the OK button.
6) In the Fonts dialog box, choose the Close button.
For help with the Fonts and Add Fonts dialog boxes, choose the Help button or press F1 while using the dialog boxes.
Windows NT
----------
To add fonts to your computer:
1) In the Control Panel window, choose the Fonts icon. The fonts already installed are listed in the Installed Fonts box.
2) Choose the Add button.
3)In the Add Fonts dialog box, select the font you want to add. If the font is not located in the current drive or directory, select the drive and directory where it is located. You can add more than one font at a time. You can also select all the fonts listed by choosing the Select All button.
4) If you are low on disk space and want to use the fonts directly from the directory (network or local) where they are located, without copying the font files to the \systemroot\SYSTEM directory, clear the Copy Fonts To Windows Directory check box.
5) Choose the OK button.
6) Choose the Close button.
For help with the Fonts and Add Fonts dialog boxes, choose the Help button or press F1 while using the dialog boxes.

BIN
classes/fonts/TREBUC.TTF Normal file

Binary file not shown.

BIN
classes/fonts/TREBUCBD.TTF Normal file

Binary file not shown.

BIN
classes/fonts/TREBUCBI.TTF Normal file

Binary file not shown.

BIN
classes/fonts/TREBUCIT.TTF Normal file

Binary file not shown.

BIN
classes/fonts/VERDANA.TTF Normal file

Binary file not shown.

BIN
classes/fonts/VERDANAB.TTF Normal file

Binary file not shown.

BIN
classes/fonts/VERDANAI.TTF Normal file

Binary file not shown.

BIN
classes/fonts/VERDANAZ.TTF Normal file

Binary file not shown.

View File

@ -0,0 +1,253 @@
<?
/********************************************************************************
************ Permissions form ********************** user.php and tools.php ****
********************************************************************************
** This function is used to create both the class permissions form, and the **
** user custom permissions form. **
********************************************************************************/
$PermissionsArray = array(
'site_leech' => 'Can leech (Does this work?).',
'site_upload' => 'Upload torrent access.',
'site_vote' => 'Request vote access.',
'site_submit_requests' => 'Request create access.',
'site_see_old_requests' => 'View old requests.',
'site_advanced_search' => 'Advanced search access.',
'site_top10' => 'Top 10 access.',
'site_advanced_top10' => 'Advanced Top 10 access.',
'site_torrents_notify' => 'Notifications access.',
'site_collages_create' => 'Collage create access.',
'site_collages_manage' => 'Collage manage access.',
'site_collages_delete' => 'Collage delete access.',
'site_collages_personal' => 'Can have a personal collage.',
'site_make_bookmarks' => 'Bookmarks access.',
'site_edit_wiki' => 'Wiki edit access.',
'site_can_invite_always' => 'Can invite past user limit.',
'site_send_unlimited_invites' => 'Unlimited invites.',
'site_moderate_requests' => 'Request moderation access.',
'site_delete_artist' => 'Can delete artists (must be able to delete torrents+requests).',
'site_moderate_forums' => 'Forum moderation access.',
'site_forums_double_post' => 'Can double post in the forums.',
'site_view_flow' => 'Can view stats and data pools.',
'site_view_full_log' => 'Can view old log entries.',
'site_view_torrent_snatchlist' => 'Can view torrent snatchlists.',
'site_recommend_own' => 'Can recommend own torrents.',
'site_manage_recommendations' => 'Recommendations management access.',
'site_delete_tag' => 'Can delete tags.',
'site_disable_ip_history' => 'Disable IP history.',
'zip_downloader' => 'Download multiple torrents at once.',
'site_debug' => 'Developer access.',
'site_proxy_images' => 'Image proxy & Anti-Canary.',
'site_search_many' => 'Can go past low limit of search results.',
'users_edit_usernames' => 'Can edit usernames.',
'users_edit_ratio' => 'Can edit anyone\'s upload/download amounts.',
'users_edit_own_ratio' => 'Can edit own upload/download amounts.',
'users_edit_titles' => 'Can edit titles.',
'users_edit_avatars' => 'Can edit avatars.',
'users_edit_invites' => 'Can edit invite numbers and cancel sent invites.',
'users_edit_watch_hours' => 'Can edit contrib watch hours.',
'users_edit_reset_keys' => 'Can reset passkey/authkey.',
'users_edit_profiles' => 'Can edit anyone\'s profile.',
'users_view_friends' => 'Can view anyone\'s friends.',
'users_reset_own_keys' => 'Can reset own passkey/authkey.',
'users_edit_password' => 'Can change passwords.',
'users_promote_below' => 'Can promote users to below current level.',
'users_promote_to' => 'Can promote users up to current level.',
'users_give_donor' => 'Can give donor access.',
'users_warn' => 'Can warn users.',
'users_disable_users' => 'Can disable users.',
'users_disable_posts' => 'Can disable users\' posting rights.',
'users_disable_any' => 'Can disable any users\' rights.',
'users_delete_users' => 'Can delete users.',
'users_view_invites' => 'Can view who user has invited.',
'users_view_seedleech' => 'Can view what a user is seeding or leeching.',
'users_view_uploaded' => 'Can view a user\'s uploads, regardless of privacy level.',
'users_view_keys' => 'Can view passkeys.',
'users_view_ips' => 'Can view IP addresses.',
'users_view_email' => 'Can view email addresses.',
'users_override_paranoia' => 'Can override paranoia.',
'users_logout' => 'Can log users out (old?).',
'users_make_invisible' => 'Can make users invisible.',
'users_mod' => 'Basic moderator tools.',
'torrents_edit' => 'Can edit any torrent.',
'torrents_delete' => 'Can delete torrents.',
'torrents_delete_fast' => 'Can delete more than 3 torrents at a time.',
'torrents_freeleech' => 'Can make torrents freeleech.',
'torrents_search_fast' => 'Rapid search (for scripts).',
'admin_manage_news' => 'Can manage news.',
'admin_manage_blog' => 'Can manage blog.',
'admin_manage_polls' => 'Can manage polls.',
'admin_manage_forums' => 'Can manage forums (add/edit/delete).',
'admin_manage_fls' => 'Can manage FLS.',
'admin_reports' => 'Can access reports system.',
'admin_advanced_user_search' => 'Can access advanced user search.',
'admin_create_users' => 'Can create users through an administrative form.',
'admin_donor_log' => 'Can view the donor log.',
'admin_manage_ipbans' => 'Can manage IP bans.',
'admin_dnu' => 'Can manage do not upload list.',
'admin_clear_cache' => 'Can clear cached.',
'admin_whitelist' => 'Can manage the list of allowed clients.',
'admin_manage_permissions' => 'Can edit permission classes/user permissions.',
'admin_schedule' => 'Can run the site schedule.',
'admin_login_watch' => 'Can manage login watch.',
'admin_manage_wiki' => 'Can manage wiki access.',
'admin_update_geoip' => 'Can update geoip data.',
'site_collages_recover' => 'Can recover \'deleted\' collages.',
'torrents_add_artist' => 'Can add artists to any group.',
'edit_unknowns' => 'Can edit unknown release information.',
'forums_polls_create' => 'Can create polls in the forums.',
'forums_polls_moderate' => 'Can feature and close polls.',
'project_team' => 'Is part of the project team.'
);
function permissions_form(){ ?>
<div class="permissions">
<div class="permission_container">
<table>
<tr>
<td class="colhead">Site</td>
</tr>
<tr>
<td>
<? display_perm('site_leech','Can leech.'); ?>
<? display_perm('site_upload','Can upload.'); ?>
<? display_perm('site_vote','Can vote on requests.'); ?>
<? display_perm('site_submit_requests','Can submit requests.'); ?>
<? display_perm('site_see_old_requests','Can see old requests.'); ?>
<? display_perm('site_advanced_search','Can use advanced search.'); ?>
<? display_perm('site_top10','Can access top 10.'); ?>
<? display_perm('site_torrents_notify','Can access torrents notifications system.'); ?>
<? display_perm('site_collages_create','Can create collages.'); ?>
<? display_perm('site_collages_manage','Can manage collages (add torrents, sorting).'); ?>
<? display_perm('site_collages_delete','Can delete collages.'); ?>
<? display_perm('site_collages_personal','Can have a personal collage.'); ?>
<? display_perm('site_advanced_top10','Can access advanced top 10.'); ?>
<? display_perm('site_make_bookmarks','Can make bookmarks.'); ?>
<? display_perm('site_edit_wiki','Can edit wiki pages.'); ?>
<? display_perm('site_can_invite_always', 'Can invite users even when invites are closed.'); ?>
<? display_perm('site_send_unlimited_invites', 'Can send unlimited invites.'); ?>
<? display_perm('site_moderate_requests', 'Can moderate any request.'); ?>
<? display_perm('site_delete_artist', 'Can delete artists (must be able to delete torrents+requests).'); ?>
<? display_perm('site_moderate_forums', 'Can moderate the forums.'); ?>
<? display_perm('site_view_flow', 'Can view site stats and data pools.'); ?>
<? display_perm('site_view_full_log', 'Can view the full site log.'); ?>
<? display_perm('site_view_torrent_snatchlist', 'Can view torrent snatchlists.'); ?>
<? display_perm('site_recommend_own', 'Can add own torrents to recommendations list.'); ?>
<? display_perm('site_manage_recommendations', 'Can edit recommendations list.'); ?>
<? display_perm('site_delete_tag', 'Can delete tags.'); ?>
<? display_perm('site_disable_ip_history', 'Disable IP history.'); ?>
<? display_perm('zip_downloader', 'Download multiple torrents at once.'); ?>
<? display_perm('site_debug', 'View site debug tables.'); ?>
<? display_perm('site_proxy_images', 'Proxy images through the server.'); ?>
<? display_perm('site_search_many', 'Can go past low limit of search results.'); ?>
<? display_perm('site_collages_recover', 'Can recover \'deleted\' collages.'); ?>
<? display_perm('site_forums_double_post', 'Can double post in the forums.'); ?>
<? display_perm('project_team', 'Part of the project team.'); ?>
<??>
</td>
</tr>
</table>
</div>
<div class="permission_container">
<table>
<tr>
<td class="colhead">Users</td>
</tr>
<tr>
<td>
<? display_perm('users_edit_usernames', 'Can edit usernames.'); ?>
<? display_perm('users_edit_ratio', 'Can edit anyone\'s upload/download amounts.'); ?>
<? display_perm('users_edit_own_ratio', 'Can edit own upload/download amounts.'); ?>
<? display_perm('users_edit_titles', 'Can edit titles.'); ?>
<? display_perm('users_edit_avatars', 'Can edit avatars.'); ?>
<? display_perm('users_edit_invites', 'Can edit invite numbers and cancel sent invites.'); ?>
<? display_perm('users_edit_watch_hours', 'Can edit contrib watch hours.'); ?>
<? display_perm('users_edit_reset_keys', 'Can reset any passkey/authkey.'); ?>
<? display_perm('users_edit_profiles', 'Can edit anyone\'s profile.'); ?>
<? display_perm('users_view_friends', 'Can view anyone\'s friends.'); ?>
<? display_perm('users_reset_own_keys', 'Can reset own passkey/authkey.'); ?>
<? display_perm('users_edit_password', 'Can change password.'); ?>
<? display_perm('users_promote_below', 'Can promote users to below current level.'); ?>
<? display_perm('users_promote_to', 'Can promote users up to current level.'); ?>
<? display_perm('users_give_donor', 'Can give donor access.'); ?>
<? display_perm('users_warn', 'Can warn users.'); ?>
<? display_perm('users_disable_users', 'Can disable users.'); ?>
<? display_perm('users_disable_posts', 'Can disable users\' posting rights.'); ?>
<? display_perm('users_disable_any', 'Can disable any users\' rights.'); ?>
<? display_perm('users_delete_users', 'Can delete anyone\'s account'); ?>
<? display_perm('users_view_invites', 'Can view who user has invited'); ?>
<? display_perm('users_view_seedleech', 'Can view what a user is seeding or leeching'); ?>
<? display_perm('users_view_uploaded', 'Can view a user\'s uploads, regardless of privacy level'); ?>
<? display_perm('users_view_keys', 'Can view passkeys'); ?>
<? display_perm('users_view_ips', 'Can view IP addresses'); ?>
<? display_perm('users_view_email', 'Can view email addresses'); ?>
<? display_perm('users_override_paranoia', 'Can override paranoia'); ?>
<? display_perm('users_make_invisible', 'Can make users invisible'); ?>
<? display_perm('users_logout', 'Can log users out'); ?>
<? display_perm('users_mod', 'Can access basic moderator tools (Admin comment)'); ?>
<??>
*Everything is only applicable to users with the same or lower class level
</td>
</tr>
</table>
</div>
<div class="permission_container">
<table>
<tr>
<td class="colhead">Torrents</td>
</tr>
<tr>
<td>
<? display_perm('forums_polls_create','Can create polls in the forums.') ?>
<? display_perm('forums_polls_moderate','Can feature and close polls.') ?>
<? display_perm('torrents_edit', 'Can edit any torrent'); ?>
<? display_perm('torrents_delete', 'Can delete torrents'); ?>
<? display_perm('torrents_delete_fast', 'Can delete more than 3 torrents at a time.'); ?>
<? display_perm('torrents_freeleech', 'Can make torrents freeleech'); ?>
<? display_perm('torrents_search_fast', 'Unlimit search frequency (for scripts).'); ?>
<? display_perm('torrents_add_artist', 'Can add artists to any group.'); ?>
<? display_perm('edit_unknowns', 'Can edit unknown release information.'); ?>
<? display_perm('site_add_logs', 'Can add logs to torrents after upload'); ?>
</td>
</tr>
</table>
</div>
<div class="permission_container">
<table>
<tr>
<td class="colhead">Administrative</td>
</tr>
<tr>
<td>
<? display_perm('admin_manage_news', 'Can manage news'); ?>
<? display_perm('admin_manage_blog', 'Can manage blog'); ?>
<? display_perm('admin_manage_polls', 'Can manage polls'); ?>
<? display_perm('admin_manage_forums', 'Can manage forums (add/edit/delete)'); ?>
<? display_perm('admin_manage_fls', 'Can manage FLS'); ?>
<? display_perm('admin_reports', 'Can access reports system'); ?>
<? display_perm('admin_advanced_user_search', 'Can access advanced user search'); ?>
<? display_perm('admin_create_users', 'Can create users through an administrative form'); ?>
<? display_perm('admin_donor_log', 'Can view the donor log'); ?>
<? display_perm('admin_manage_ipbans', 'Can manage IP bans'); ?>
<? display_perm('admin_dnu', 'Can manage do not upload list'); ?>
<? display_perm('admin_clear_cache', 'Can clear cached pages'); ?>
<? display_perm('admin_whitelist', 'Can manage the list of allowed clients.'); ?>
<? display_perm('admin_manage_permissions', 'Can edit permission classes/user permissions.'); ?>
<? display_perm('admin_schedule', 'Can run the site schedule.'); ?>
<? display_perm('admin_login_watch', 'Can manage login watch.'); ?>
<? display_perm('admin_manage_wiki', 'Can manage wiki access.'); ?>
<? display_perm('admin_update_geoip', 'Can update geoip data.'); ?>
<??>
</td>
</tr>
</table>
</div>
<div class="submit_container"><input type="submit" name="submit" value="Save Permission Class" /></div>
</div>
<? } ?>

13
classes/regex.php Normal file
View File

@ -0,0 +1,13 @@
<?
//resource_type://username:password@domain:port/path?query_string#anchor
define('RESOURCE_REGEX','(https?|ftps?):\/\/');
define('IP_REGEX','(\d{1,3}\.){3}\d{1,3}');
define('DOMAIN_REGEX','(ssl.)?(www.)?[a-z0-9-\.]{1,255}\.[a-zA-Z]{2,6}');
define('PORT_REGEX', '\d{1,5}');
define('URL_REGEX','('.RESOURCE_REGEX.')('.IP_REGEX.'|'.DOMAIN_REGEX.')(:'.PORT_REGEX.')?(\/\S*)*');
define('EMAIL_REGEX','[_a-z0-9-]+([.+][_a-z0-9-]+)*@'.DOMAIN_REGEX);
define('IMAGE_REGEX', URL_REGEX.'\/\S+\.(jpg|jpeg|tif|tiff|png|gif|bmp)(\?\S*)?');
define('SITELINK_REGEX', RESOURCE_REGEX.'(ssl.)?'.preg_quote(NONSSL_SITE_URL, '/').'');
define('TORRENT_REGEX', SITELINK_REGEX.'\/torrents.php\?(id=\d{1,10}\&)?torrentid=\d{1,10}');
define('TORRENT_GROUP_REGEX', SITELINK_REGEX.'\/torrents.php\?id=\d{1,10}\&(torrentid=\d{1,10})?');
?>

1880
classes/script_start.php Normal file

File diff suppressed because it is too large Load Diff

1692
classes/sphinxapi.php Normal file

File diff suppressed because it is too large Load Diff

4
collage.php Normal file
View File

@ -0,0 +1,4 @@
<?
$_SERVER['SCRIPT_FILENAME'] = 'collages.php'; // PHP CLI fix
define('ERROR_EXCEPTION', true);
require('classes/script_start.php');

3
collages.php Normal file
View File

@ -0,0 +1,3 @@
<?
define('ERROR_EXCEPTION', true);
require('classes/script_start.php');

3
comments.php Normal file
View File

@ -0,0 +1,3 @@
<?
define('ERROR_EXCEPTION', true);
require('classes/script_start.php');

87
defer-bug.php Normal file
View File

@ -0,0 +1,87 @@
<?
function make_utf8($Str) {
if ($Str!="") {
if (is_utf8($Str)) { $Encoding="UTF-8"; }
if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); }
if (empty($Encoding)) { $Encoding="ISO-8859-1"; }
if ($Encoding=="UTF-8") { return $Str; }
else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); }
}
}
function is_utf8($Str) {
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] // ASCII
| [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16
)*$%xs', $Str
);
}
function is_number($Str) {
$Return = true;
if ($Str < 0) { $Return = false; }
// We're converting input to a int, then string and comparing to original
$Return = ($Str == strval(intval($Str)) ? true : false);
return $Return;
}
function display_str($Str) {
if (empty($Str)) {
return '';
}
if ($Str!='' && !is_number($Str)) {
$Str=make_utf8($Str);
$Str=mb_convert_encoding($Str,"HTML-ENTITIES","UTF-8");
$Str=preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m","&amp;",$Str);
$Replace = array(
"'",'"',"<",">",
'&#128;','&#130;','&#131;','&#132;','&#133;','&#134;','&#135;','&#136;','&#137;','&#138;','&#139;','&#140;','&#142;','&#145;','&#146;','&#147;','&#148;','&#149;','&#150;','&#151;','&#152;','&#153;','&#154;','&#155;','&#156;','&#158;','&#159;'
);
$With=array(
'&#39;','&quot;','&lt;','&gt;',
'&#8364;','&#8218;','&#402;','&#8222;','&#8230;','&#8224;','&#8225;','&#710;','&#8240;','&#352;','&#8249;','&#338;','&#381;','&#8216;','&#8217;','&#8220;','&#8221;','&#8226;','&#8211;','&#8212;','&#732;','&#8482;','&#353;','&#8250;','&#339;','&#382;','&#376;'
);
$Str=str_replace($Replace,$With,$Str);
}
return $Str;
}
require('classes/class_useragent.php'); //Require the useragent class
$UA = new USER_AGENT;
$Browser = $UA->browser($_SERVER['HTTP_USER_AGENT']);
$OperatingSystem = $UA->operating_system($_SERVER['HTTP_USER_AGENT']);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>&lt;script&gt; Defer Bug</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js" type="text/javascript" defer="defer"></script>
</head>
<body>
<h2>Defer bug test (Gecko 1.9.2+)</h2>
<p>This page showcases issues with browsers and defer loading with the preservation of content order.</p>
<p>As one can see in this demo, the implementation of the HTML5 changes to &lt;script defer&gt; (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=518104">1</a>) has resulted in several small issues, originating from the way this has been used historically. Up until the past year, javascript execution has been painfully slow, to an extent that things like Google Analytics advised the placement of their javascript in file footers (a contradiction to another part of the spec). The defer attribute has been used in such cases to allowe ECMAScript to remain in the correct inclusion location without blocking the download of content or the rendering of the webpage. This lowered the percieved load time, the <em>most</em> important number in web development (notably for encouraging users to return). Because of this change however, not only has this percieved performance gain been sacrificed, but a relatively serious backwords compatibility issue for sites using defer in their natural code execution pattern.</p>
<p>Because of this combination of breaking various script loading patterns, a decrease in user percieved performance, the fact that all other browsers thus far have opted out of this adaptation of the spec, and the resulting encouragement this would give web developers to include scripts outside the page header; I am humbly noting that this additional 'clarification' contained in the HTML5 spec is flawed in nature and should be reverted to it's prior method.</p>
<strong>Browser Info</strong>
<ul>
<li>Detected platform: <?=$OperatingSystem?></li>
<li>Detected browser: <?=$Browser?></li>
<li>User-Agent: <?=display_str($_SERVER['HTTP_USER_AGENT'])?></li>
</ul>
<p>To clarify for the confused: if you get the alert, your browser has this bug, if you do not get the alert, your browser is working fine.</p>
<script type="text/javascript" defer="defer">
if (typeof($) === 'undefined') {
alert('jQuery was not loaded prior to inline code execution');
}
</script>
</body>
</html>

3
delays.php Normal file
View File

@ -0,0 +1,3 @@
<?
define('ERROR_EXCEPTION', true);
require('classes/script_start.php');

59
design/privatefooter.php Normal file
View File

@ -0,0 +1,59 @@
</div>
<div id="footer">
<? if (!empty($Options['disclaimer'])) { ?>
<br /><br />
<div id="disclaimer_container" class="thin" style="text-align:center; margin-bottom:20px;">
None of the files shown here are actually hosted on this server. The links are provided solely by this site's users. These BitTorrent files are meant for the distribution of backup files. By downloading the BitTorrent file, you are claiming that you own the original file. The administrator of this site (http://<?=NONSSL_SITE_URL?>) holds NO RESPONSIBILITY if these files are misused in any way and cannot be held responsible for what its users post, or any other actions of it.
</div>
<?
}
if (count($UserSessions)>1) {
foreach ($UserSessions as $ThisSessionID => $Session) {
if ($ThisSessionID != $SessionID) {
$LastActive = $Session;
break;
}
}
}
$Load = sys_getloadavg();
?>
<p>
Site and design &copy; <?=date("Y")?> <?=SITE_NAME?>
</p>
<? if(!empty($LastActive)){ ?><p><a href="user.php?action=sessions" title="Manage Sessions">Last activity <?=time_diff($LastActive['LastUpdate'])?> from <?=$LastActive['IP']?>.</a></p><? } ?>
<p>
<strong>Time:</strong> <?=number_format(((microtime(true)-$ScriptStartTime)*1000),5)?> ms
<strong>Used:</strong> <?=get_size(memory_get_usage(true))?>
<strong>Load:</strong> <?=number_format($Load[0],2).' '.number_format($Load[1],2).' '.number_format($Load[2],2)?>
<strong>Date:</strong> <?=date('M d Y, H:i')?>
</p>
</div>
<? if (DEBUG_MODE || check_perms('site_debug')) { ?>
<!-- Begin Debugging -->
<div id="site_debug">
<?
$Debug->flag_table();
$Debug->error_table();
$Debug->sphinx_table();
$Debug->query_table();
$Debug->cache_table();
?>
</div>
<!-- End Debugging -->
<? } ?>
</div>
<div id="lightbox" class="lightbox hidden"></div>
<div id="curtain" class="curtain hidden"></div>
<!-- Extra divs, for stylesheet developers to add imagery -->
<div id="extra1"><span></span></div>
<div id="extra2"><span></span></div>
<div id="extra3"><span></span></div>
<div id="extra4"><span></span></div>
<div id="extra5"><span></span></div>
<div id="extra6"><span></span></div>
</body>
</html>

407
design/privateheader.php Normal file
View File

@ -0,0 +1,407 @@
<?
define('FOOTER_FILE', SERVER_ROOT.'/design/privatefooter.php');
$HTTPS = ($_SERVER['SERVER_PORT'] == 443) ? 'ssl_' : '';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><?=display_str($PageTitle)?></title>
<meta http-equiv="X-UA-Compatible" content="chrome=1;IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="shortcut icon" href="favicon.ico" />
<link rel="search" type="application/opensearchdescription+xml" title="<?=SITE_NAME?> Artists" href="opensearch.php?type=artists" />
<link rel="search" type="application/opensearchdescription+xml" title="<?=SITE_NAME?> Torrents" href="opensearch.php?type=torrents" />
<link rel="search" type="application/opensearchdescription+xml" title="<?=SITE_NAME?> Requests" href="opensearch.php?type=requests" />
<link rel="search" type="application/opensearchdescription+xml" title="<?=SITE_NAME?> Forums" href="opensearch.php?type=forums" />
<link rel="search" type="application/opensearchdescription+xml" title="<?=SITE_NAME?> Log" href="opensearch.php?type=log" />
<link rel="search" type="application/opensearchdescription+xml" title="<?=SITE_NAME?> Users" href="opensearch.php?type=users" />
<link rel="search" type="application/opensearchdescription+xml" title="<?=SITE_NAME?> Wiki" href="opensearch.php?type=wiki" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=feed_news&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - News" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=feed_blog&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - Blog" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_notify_<?=$LoggedUser['torrent_pass']?>&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - P.T.N." />
<? if(isset($LoggedUser['Notify'])) {
foreach($LoggedUser['Notify'] as $Filter) {
list($FilterID, $FilterName) = $Filter;
?>
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_notify_<?=$FilterID?>_<?=$LoggedUser['torrent_pass']?>&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>&amp;name=<?=urlencode($FilterName)?>" title="<?=SITE_NAME?> - <?=display_str($FilterName)?>" />
<? }
}?>
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_all&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - All Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_music&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - Music Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_apps&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - Application Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_ebooks&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - E-Book Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_abooks&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - Audiobooks Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_evids&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - E-Learning Video Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_comedy&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - Comedy Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_comics&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - Comic Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_mp3&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - MP3 Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_flac&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - FLAC Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_vinyl&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - Vinyl Sourced Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_lossless&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - Lossless Torrents" />
<link rel="alternate" type="application/rss+xml" href="feeds.php?feed=torrents_lossless24&amp;user=<?=$LoggedUser['ID']?>&amp;auth=<?=$LoggedUser['RSS_Auth']?>&amp;passkey=<?=$LoggedUser['torrent_pass']?>&amp;authkey=<?=$LoggedUser['AuthKey']?>" title="<?=SITE_NAME?> - 24bit Lossless Torrents" />
<? if ($Mobile) { ?>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0, user-scalable=no;"/>
<link href="<?=STATIC_SERVER ?>styles/mobile/style.css" rel="stylesheet" type="text/css" />
<? } else { ?>
<? if (empty($LoggedUser['StyleURL'])) { ?>
<link href="<?=STATIC_SERVER?>styles/<?=$LoggedUser['StyleName']?>/style.css?v=<?=filemtime(SERVER_ROOT.'/static/styles/'.$LoggedUser['StyleName'].'/style.css')?>" title="<?=$LoggedUser['StyleName']?>" rel="stylesheet" type="text/css" media="screen" />
<? } else { ?>
<link href="<?=$LoggedUser['StyleURL']?>" title="External CSS" rel="stylesheet" type="text/css" media="screen" />
<? } ?>
<? } ?>
<link href="<?=STATIC_SERVER?>styles/global.css?v=<?=filemtime(SERVER_ROOT.'/static/styles/global.css')?>" rel="stylesheet" type="text/css" />
<script src="<?=STATIC_SERVER?>functions/sizzle.js" type="text/javascript"></script>
<script src="<?=STATIC_SERVER?>functions/script_start.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/script_start.js')?>" type="text/javascript"></script>
<script src="<?=STATIC_SERVER?>functions/class_ajax.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/class_ajax.js')?>" type="text/javascript"></script>
<script type="text/javascript">//<![CDATA[
var authkey = "<?=$LoggedUser['AuthKey']?>";
var userid = <?=$LoggedUser['ID']?>;
//]]></script>
<script src="<?=STATIC_SERVER?>functions/global.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/global.js')?>" type="text/javascript"></script>
<?
$Scripts=explode(',',$JSIncludes);
foreach ($Scripts as $Script) {
if (empty($Script)) { continue; }
?>
<script src="<?=STATIC_SERVER?>functions/<?=$Script?>.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/'.$Script.'.js')?>" type="text/javascript"></script>
<? }
if ($Mobile) { ?>
<script src="<?=STATIC_SERVER?>styles/mobile/style.js" type="text/javascript"></script>
<? } ?>
</head>
<body id="<?=$Document == 'collages' ? 'collage' : $Document?>" <?= ((!$Mobile && $LoggedUser['Rippy'] == 'On') ? 'onload="say()"' : '') ?>>
<div id="wrapper">
<h1 class="hidden"><?=SITE_NAME?></h1>
<div id="header">
<div id="logo"><a href="index.php"></a></div>
<div id="userinfo">
<ul id="userinfo_username">
<li id="nav_userinfo"><a href="user.php?id=<?=$LoggedUser['ID']?>" class="username"><?=$LoggedUser['Username']?></a></li>
<li id="nav_useredit" class="brackets"><a href="user.php?action=edit&amp;userid=<?=$LoggedUser['ID']?>">Edit</a></li>
<li id="nav_logout" class="brackets"><a href="logout.php?auth=<?=$LoggedUser['AuthKey']?>">Logout</a></li>
</ul>
<ul id="userinfo_major">
<li id="nav_upload" class="brackets"><a href="upload.php">Upload</a></li>
<?
if(check_perms('site_send_unlimited_invites')) {
$Invites = ' (∞)';
} elseif ($LoggedUser['Invites']>0) {
$Invites = ' ('.$LoggedUser['Invites'].')';
} else {
$Invites = '';
}
?>
<li id="nav_invite" class="brackets"><a href="user.php?action=invite">Invite<?=$Invites?></a></li>
<li id="nav_donate" class="brackets"><a href="donate.php">Donate</a></li>
</ul>
<ul id="userinfo_stats">
<li id="stats_seeding"><a href="torrents.php?type=seeding&amp;userid=<?=$LoggedUser['ID']?>">Up</a>: <span class="stat"><?=get_size($LoggedUser['BytesUploaded'])?></span></li>
<li id="stats_leeching"><a href="torrents.php?type=leeching&amp;userid=<?=$LoggedUser['ID']?>">Down</a>: <span class="stat"><?=get_size($LoggedUser['BytesDownloaded'])?></span></li>
<li id="stats_ratio">Ratio: <span class="stat"><?=ratio($LoggedUser['BytesUploaded'], $LoggedUser['BytesDownloaded'])?></span></li>
<? if(!empty($LoggedUser['RequiredRatio'])) {?>
<li id="stats_required"><a href="rules.php?p=ratio">Required</a>: <span class="stat"><?=number_format($LoggedUser['RequiredRatio'], 2)?></span></li>
<? } ?>
</ul>
<ul id="userinfo_minor">
<li id="nav_inbox"><a onmousedown="Stats('inbox');" href="inbox.php">Inbox</a></li>
<li id="nav_staffinbox"><a onmousedown="Stats('staffpm');" href="staffpm.php">Staff Inbox</a></li>
<li id="nav_uploaded"><a onmousedown="Stats('uploads');" href="torrents.php?type=uploaded&amp;userid=<?=$LoggedUser['ID']?>">Uploads</a></li>
<li id="nav_bookmarks"><a onmousedown="Stats('bookmarks');" href="bookmarks.php">Bookmarks</a></li>
<? if (check_perms('site_torrents_notify')) { ?>
<li id="nav_notifications"><a onmousedown="Stats('notifications');" href="user.php?action=notify">Notifications</a></li>
<? }
//Subscriptions
$NewSubscriptions = $Cache->get_value('subscriptions_user_new_'.$LoggedUser['ID']);
if($NewSubscriptions === FALSE) {
$DB->query("SELECT COUNT(s.TopicID)
FROM users_subscriptions AS s
JOIN forums_last_read_topics AS l ON s.UserID = l.UserID AND s.TopicID = l.TopicID
JOIN forums_topics AS t ON l.TopicID = t.ID
JOIN forums AS f ON t.ForumID = f.ID
WHERE f.MinClassRead <= ".$LoggedUser['Class']."
AND l.PostID < t.LastPostID
AND s.UserID = ".$LoggedUser['ID']);
list($NewSubscriptions) = $DB->next_record();
$Cache->cache_value('subscriptions_user_new_'.$LoggedUser['ID'], $NewSubscriptions, 0);
}
?>
<li id="nav_subscriptions"><a onmousedown="Stats('subscriptions');" href="userhistory.php?action=subscriptions"<?=($NewSubscriptions ? ' class="new-subscriptions"' : '')?>>Subscriptions</a></li>
<li id="nav_comments"><a onmousedown="Stats('comments');" href="comments.php">Comments</a></li>
<li id="nav_friends"><a onmousedown="Stats('friends');" href="friends.php">Friends</a></li>
</ul>
</div>
<div id="menu">
<h4 class="hidden">Site Menu</h4>
<ul>
<li id="nav_index"><a href="index.php">Home</a></li>
<li id="nav_torrents"><a href="torrents.php">Torrents</a></li>
<li id="nav_collages"><a href="collages.php">Collages</a></li>
<li id="nav_requests"><a href="requests.php">Requests</a></li>
<li id="nav_forums"><a href="forums.php">Forums</a></li>
<li id="nav_irc"><a href="chat.php">IRC</a></li>
<li id="nav_top10"><a href="top10.php">Top 10</a></li>
<li id="nav_rules"><a href="rules.php">Rules</a></li>
<li id="nav_wiki"><a href="wiki.php">Wiki</a></li>
<li id="nav_staff"><a href="staff.php">Staff</a></li>
</ul>
</div>
<?
//Start handling alert bars
$Alerts = array();
$ModBar = array();
// News
$MyNews = $LoggedUser['LastReadNews'];
$CurrentNews = $Cache->get_value('news_latest_id');
if ($CurrentNews === false) {
$DB->query("SELECT ID FROM news ORDER BY Time DESC LIMIT 1");
if ($DB->record_count() == 1) {
list($CurrentNews) = $DB->next_record();
} else {
$CurrentNews = -1;
}
$Cache->cache_value('news_latest_id', $CurrentNews, 0);
}
if ($MyNews < $CurrentNews) {
$Alerts[] = '<a href="index.php">'.'New Announcement!'.'</a>';
}
//Staff PM
$NewStaffPMs = $Cache->get_value('staff_pm_new_'.$LoggedUser['ID']);
if ($NewStaffPMs === false) {
$DB->query("SELECT COUNT(ID) FROM staff_pm_conversations WHERE UserID='".$LoggedUser['ID']."' AND Unread = '1'");
list($NewStaffPMs) = $DB->next_record();
$Cache->cache_value('staff_pm_new_'.$LoggedUser['ID'], $NewStaffPMs, 0);
}
if ($NewStaffPMs > 0) {
$Alerts[] = '<a href="staffpm.php">'.'You have '.$NewStaffPMs.(($NewStaffPMs > 1) ? ' new staff messages' : ' new staff message').'</a>';
}
//Inbox
$NewMessages = $Cache->get_value('inbox_new_'.$LoggedUser['ID']);
if ($NewMessages === false) {
$DB->query("SELECT COUNT(UnRead) FROM pm_conversations_users WHERE UserID='".$LoggedUser['ID']."' AND UnRead = '1' AND InInbox = '1'");
list($NewMessages) = $DB->next_record();
$Cache->cache_value('inbox_new_'.$LoggedUser['ID'], $NewMessages, 0);
}
if ($NewMessages > 0) {
$Alerts[] = '<a href="inbox.php">'.'You have '.$NewMessages.(($NewMessages > 1) ? ' new messages' : ' new message').'</a>';
}
if($LoggedUser['RatioWatch']){
$Alerts[] = '<a href="rules.php?p=ratio">'.'Ratio Watch'.'</a>: '.'You have '.time_diff($LoggedUser['RatioWatchEnds'], 3).' to get your ratio over your required ratio.';
}
if (check_perms('site_torrents_notify')) {
$NewNotifications = $Cache->get_value('notifications_new_'.$LoggedUser['ID']);
if ($NewNotifications === false) {
$DB->query("SELECT COUNT(UserID) FROM users_notify_torrents WHERE UserID='$LoggedUser[ID]' AND UnRead='1'");
list($NewNotifications) = $DB->next_record();
/* if($NewNotifications && !check_perms('site_torrents_notify')) {
$DB->query("DELETE FROM users_notify_torrents WHERE UserID='$LoggedUser[ID]'");
$DB->query("DELETE FROM users_notify_filters WHERE UserID='$LoggedUser[ID]'");
} */
$Cache->cache_value('notifications_new_'.$LoggedUser['ID'], $NewNotifications, 0);
}
if ($NewNotifications > 0) {
$Alerts[] = '<a href="torrents.php?action=notify">'.'You have '.$NewNotifications.(($NewNotifications > 1) ? ' new torrent notifications' : ' new torrent notification').'</a>';
}
}
if (check_perms('users_mod')) {
$ModBar[] = '<a href="tools.php">'.'Toolbox'.'</a>';
$NumStaffPMs = $Cache->get_value('num_staff_pms_'.$LoggedUser['ID']);
if ($NumStaffPMs === false) {
$DB->query("SELECT COUNT(ID) FROM staff_pm_conversations WHERE Status='Unanswered' AND (AssignedToUser=".$LoggedUser['ID']." OR Level=".$LoggedUser['Class'].")");
list($NumStaffPMs) = $DB->next_record();
$Cache->cache_value('num_staff_pms_'.$LoggedUser['ID'], $NumStaffPMs , 1000);
}
if ($NumStaffPMs > 0) {
$ModBar[] = '<a href="staffpm.php">'.$NumStaffPMs.' Staff PMs</a>';
}
}
if(check_perms('admin_reports')) {
$NumTorrentReports = $Cache->get_value('num_torrent_reportsv2');
if ($NumTorrentReports === false) {
$DB->query("SELECT COUNT(ID) FROM reportsv2 WHERE Status='New'");
list($NumTorrentReports) = $DB->next_record();
$Cache->cache_value('num_torrent_reportsv2', $NumTorrentReports, 0);
}
$ModBar[] = '<a href="reportsv2.php">'.$NumTorrentReports.(($NumTorrentReports == 1) ? ' Report' : ' Reports').'</a>';
}
if(check_perms('admin_reports')) {
$NumOtherReports = $Cache->get_value('num_other_reports');
if ($NumOtherReports === false) {
$DB->query("SELECT COUNT(ID) FROM reports WHERE Status='New'");
list($NumOtherReports) = $DB->next_record();
$Cache->cache_value('num_other_reports', $NumOtherReports, 0);
}
if ($NumOtherReports > 0) {
$ModBar[] = '<a href="reports.php">'.$NumOtherReports.(($NumTorrentReports == 1) ? ' Other Report' : ' Other Reports').'</a>';
}
} else if(check_perms('project_team')) {
$NumUpdateReports = $Cache->get_value('num_update_reports');
if ($NumUpdateReports === false) {
$DB->query("SELECT COUNT(ID) FROM reports WHERE Status='New' AND Type = 'request_update'");
list($NumUpdateReports) = $DB->next_record();
$Cache->cache_value('num_update_reports', $NumUpdateReports, 0);
}
if ($NumUpdateReports > 0) {
$ModBar[] = '<a href="reports.php">'.'Request update reports'.'</a>';
}
}
if (!empty($Alerts) || !empty($ModBar)) {
?>
<div id="alerts">
<? foreach ($Alerts as $Alert) { ?>
<div class="alertbar"><?=$Alert?></div>
<? }
if (!empty($ModBar)) { ?>
<div class="alertbar blend"><?=implode(' | ',$ModBar)?></div>
<? } ?>
</div>
<?
}
//Done handling alertbars
if(!$Mobile && $LoggedUser['Rippy'] != 'Off') {
switch($LoggedUser['Rippy']) {
case 'PM' :
$Says = $Cache->get_value('rippy_message_'.$LoggedUser['ID']);
if($Says === false) {
$Says = $Cache->get_value('global_rippy_message');
}
$Show = ($Says !== false);
$Cache->delete_value('rippy_message_'.$LoggedUser['ID']);
break;
case 'On' :
$Show = true;
$Says = '';
break;
/* Uncomment to always show globals
case 'Off' :
$Says = $Cache->get_value('global_rippy_message');
$Show = ($Says !== false);
break;
*/
}
if($Show) {
?>
<div class="rippywrap">
<div id="bubble" style="display: <?=($Says ? 'block' : 'none')?>">
<span class="rbt"></span>
<span id="rippy-says" class="rbm"><?=$Says?></span>
<span class="rbb"></span>
</div>
<div class="rippy" onclick="rippyclick();"></div>
</div>
<?
}
}
?>
<div id="searchbars">
<ul>
<li id="searchbar_torrents">
<span class="hidden">Torrents: </span>
<form action="torrents.php" method="get">
<? if(isset($LoggedUser['SearchType']) && $LoggedUser['SearchType']) { // Advanced search ?>
<input type="hidden" name="action" value="advanced" />
<? } ?>
<input
accesskey="t"
spellcheck="false"
onfocus="if (this.value == 'Torrents') this.value='';"
onblur="if (this.value == '') this.value='Torrents';"
<? if(isset($LoggedUser['SearchType']) && $LoggedUser['SearchType']) { // Advanced search ?>
value="Torrents" type="text" name="groupname" size="17"
<? } else { ?>
value="Torrents" type="text" name="searchstr" size="17"
<? } ?>
/>
</form>
</li>
<li id="searchbar_artists">
<span class="hidden">Artist: </span>
<form action="artist.php" method="get">
</form>
</li>
<li id="searchbar_requests">
<span class="hidden">Requests: </span>
<form action="requests.php" method="get">
<input
spellcheck="false"
onfocus="if (this.value == 'Requests') this.value='';"
onblur="if (this.value == '') this.value='Requests';"
value="Requests" type="text" name="search" size="17"
/>
</form>
</li>
<li id="searchbar_forums">
<span class="hidden">Forums: </span>
<form action="forums.php" method="get">
<input value="search" type="hidden" name="action" />
<input
onfocus="if (this.value == 'Forums') this.value='';"
onblur="if (this.value == '') this.value='Forums';"
value="Forums" type="text" name="search" size="17"
/>
</form>
</li>
<!--
<li id="searchbar_wiki">
<span class="hidden">Wiki: </span>
<form action="wiki.php" method="get">
<input type="hidden" name="action" value="search">
<input
onfocus="if (this.value == 'Wiki') this.value='';"
onblur="if (this.value == '') this.value='Wiki';"
value="Wiki" type="text" name="search" size="17"
/>
</form>
</li>
-->
<li id="searchbar_log">
<span class="hidden">Log: </span>
<form action="log.php" method="get">
<input
onfocus="if (this.value == 'Log') this.value='';"
onblur="if (this.value == '') this.value='Log';"
value="Log" type="text" name="search" size="17"
/>
</form>
</li>
<li id="searchbar_users">
<span class="hidden">Users: </span>
<form action="user.php" method="get">
<input type="hidden" name="action" value="search" />
<input
onfocus="if (this.value == 'Users') this.value='';"
onblur="if (this.value == '') this.value='Users';"
value="Users" type="text" name="search" size="20"
/>
</form>
</li>
</ul>
</div>
</div>
<div id="content">

8
design/publicfooter.php Normal file
View File

@ -0,0 +1,8 @@
</td>
</tr>
</table>
<div id="foot">
<span><a href="#"><?=SITE_NAME?></a> | <a href="http://what-network.net">What-Network</a> | <a href="http://what.cd/gazelle/">Project Gazelle</a></span>
</div>
</body>
</html>

48
design/publicheader.php Normal file
View File

@ -0,0 +1,48 @@
<?
global $LoggedUser, $Languages, $SSL;
define('FOOTER_FILE',SERVER_ROOT.'/design/publicfooter.php');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><?=display_str($PageTitle)?></title>
<meta http-equiv="X-UA-Compatible" content="chrome=1;IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="shortcut icon" href="favicon.ico" />
<? if ($Mobile) { ?>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0, user-scalable=no;"/>
<link href="<?=STATIC_SERVER ?>styles/mobile/style.css?v=<?=filemtime(SERVER_ROOT.'/static/mobile/style.css')?>" rel="stylesheet" type="text/css" />
<? } else { ?>
<link href="<?=STATIC_SERVER ?>styles/public/style.css?v=<?=filemtime(SERVER_ROOT.'/static/styles/public/style.css')?>" rel="stylesheet" type="text/css" />
<? } ?>
<script src="<?=STATIC_SERVER?>functions/sizzle.js" type="text/javascript"></script>
<script src="<?=STATIC_SERVER?>functions/script_start.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/script_start.js')?>" type="text/javascript"></script>
<script src="<?=STATIC_SERVER?>functions/class_ajax.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/class_ajax.js')?>" type="text/javascript"></script>
<script src="<?=STATIC_SERVER?>functions/class_cookie.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/class_cookie.js')?>" type="text/javascript"></script>
<script src="<?=STATIC_SERVER?>functions/class_storage.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/class_storage.js')?>" type="text/javascript"></script>
<script src="<?=STATIC_SERVER?>functions/global.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/global.js')?>" type="text/javascript"></script>
<? if ($Mobile) { ?>
<script src="<?=STATIC_SERVER?>styles/mobile/style.js?v=<?=filemtime(SERVER_ROOT.'/static/mobile/style.js')?>" type="text/javascript"></script>
<? }
?>
</head>
<body>
<div id="head">
<?=($SSL)?'<span>SSL</span>':''?>
<?
?>
</div>
<table id="maincontent">
<tr>
<td align="center" valign="middle">
<div id="logo">
<ul>
<li><a href="index.php<?=($Lang != DEFAULT_LOCALE ? '?lang='.$Lang : '')?>">Home</a></li>
<li><a href="login.php<?=($Lang != DEFAULT_LOCALE ? '?lang='.$Lang : '')?>">Login</a></li>
<? if (OPEN_REGISTRATION) { ?>
<li><a href="register.php<?=($Lang != DEFAULT_LOCALE ? '?lang='.$Lang : '')?>">Register</a></li>
</ul>
<? } ?>
</div>

1
donate.php Normal file
View File

@ -0,0 +1 @@
<? require('classes/script_start.php');

1
error.php Normal file
View File

@ -0,0 +1 @@
<? require("classes/script_start.php");

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

90
feeds.php Normal file
View File

@ -0,0 +1,90 @@
<?
/*-- Feed Start Class ----------------------------------*/
/*------------------------------------------------------*/
/* Simplified version of script_start, used for the */
/* sitewide RSS system. */
/*------------------------------------------------------*/
/********************************************************/
//Lets prevent people from clearing feeds
if (isset($_GET['clearcache'])) {
unset($_GET['clearcache']);
}
require 'classes/config.php'; //The config contains all site wide configuration information as well as memcached rules
require(SERVER_ROOT.'/classes/class_cache.php'); //Require the caching class
require(SERVER_ROOT.'/classes/class_feed.php'); //Require the caching class
$Cache = NEW CACHE; //Load the caching class
$Feed = NEW FEED; //Lead the time class
function check_perms() {
return false;
}
function is_number($Str) {
if ($Str < 0) { return false; }
// We're converting input to a int, then string and comparing to original
return ($Str == strval(intval($Str)) ? true : false);
}
function display_str($Str) {
if ($Str!="") {
$Str=make_utf8($Str);
$Str=mb_convert_encoding($Str,"HTML-ENTITIES","UTF-8");
$Str=preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m","&amp;",$Str);
$Replace = array(
"'",'"',"<",">",
'&#128;','&#130;','&#131;','&#132;','&#133;','&#134;','&#135;','&#136;','&#137;','&#138;','&#139;','&#140;','&#142;','&#145;','&#146;','&#147;','&#148;','&#149;','&#150;','&#151;','&#152;','&#153;','&#154;','&#155;','&#156;','&#158;','&#159;'
);
$With=array(
'&#39;','&quot;','&lt;','&gt;',
'&#8364;','&#8218;','&#402;','&#8222;','&#8230;','&#8224;','&#8225;','&#710;','&#8240;','&#352;','&#8249;','&#338;','&#381;','&#8216;','&#8217;','&#8220;','&#8221;','&#8226;','&#8211;','&#8212;','&#732;','&#8482;','&#353;','&#8250;','&#339;','&#382;','&#376;'
);
$Str=str_replace($Replace,$With,$Str);
}
return $Str;
}
function make_utf8($Str) {
if ($Str!="") {
if (is_utf8($Str)) { $Encoding="UTF-8"; }
if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); }
if (empty($Encoding)) { $Encoding="ISO-8859-1"; }
if ($Encoding=="UTF-8") { return $Str; }
else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); }
}
}
function is_utf8($Str) {
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] // ASCII
| [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16
)*$%xs', $Str
);
}
function display_array($Array, $Escape = array()) {
foreach ($Array as $Key => $Val) {
if((!is_array($Escape) && $Escape == true) || !in_array($Key, $Escape)) {
$Array[$Key] = display_str($Val);
}
}
return $Array;
}
header('Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0');
header('Pragma:');
header('Expires: '.date('D, d M Y H:i:s', time()+(2*60*60)).' GMT');
header('Last-Modified: '.date('D, d M Y H:i:s').' GMT');
require(SERVER_ROOT.'/sections/feeds/index.php');

18
flush.php Normal file
View File

@ -0,0 +1,18 @@
<?
ob_start();
echo '0';
ob_flush();
sleep(20);
echo '20';
ob_flush();
sleep(20);
echo '40';
ob_flush();
sleep(20);
echo '60';
ob_end_flush();

3
forums.php Normal file
View File

@ -0,0 +1,3 @@
<?
define('ERROR_EXCEPTION', true);
require('classes/script_start.php');

3
friends.php Normal file
View File

@ -0,0 +1,3 @@
<?
define('ERROR_EXCEPTION', true);
require('classes/script_start.php');

1549
gazelle.sql Normal file

File diff suppressed because one or more lines are too long

1
gazelle_version Normal file
View File

@ -0,0 +1 @@
2011-03-27 Revision 0

167
image.php Normal file
View File

@ -0,0 +1,167 @@
<?
/*-- Image Start Class ---------------------------------*/
/*------------------------------------------------------*/
/* Simplified version of script_start, used for the */
/* sitewide image proxy. */
/*------------------------------------------------------*/
/********************************************************/
if(isset($_SERVER['http_if_modified_since'])) {
header("Status: 304 Not Modified");
die();
}
header('Expires: '.date('D, d-M-Y H:i:s \U\T\C',time()+3600*24*120)); //120 days
header('Last-Modified: '.date('D, d-M-Y H:i:s \U\T\C',time()));
require('classes/config.php'); //The config contains all site wide configuration information as well as memcached rules
if (!extension_loaded('gd')) { error('nogd'); }
require(SERVER_ROOT.'/classes/class_cache.php'); //Require the caching class
require(SERVER_ROOT.'/classes/class_encrypt.php'); //Require the encryption class
require(SERVER_ROOT.'/classes/regex.php');
$Cache = NEW CACHE; //Load the caching class
$Enc = NEW CRYPT; //Load the encryption class
if (isset($_COOKIE['session'])) { $LoginCookie=$Enc->decrypt($_COOKIE['session']); }
if(isset($LoginCookie)) {
list($SessionID, $UserID)=explode("|~|",$Enc->decrypt($LoginCookie));
$UserID = (int)$UserID;
$UserInfo = $Cache->get_value('user_info_'.$UserID);
$Permissions = $Cache->get_value('perm_'.$UserInfo['PermissionID']);
}
function check_perms($PermissionName) {
global $Permissions;
return (isset($Permissions['Permissions'][$PermissionName])) ? true : false;
}
function error($Type) {
header('Content-type: image/gif');
die(file_get_contents(SERVER_ROOT.'/sections/image/'.$Type.'.gif'));
}
function invisible($Image) {
$Count = imagecolorstotal($Image);
if ($Count == 0) { return false; }
$TotalAlpha = 0;
for ($i=0; $i<$Count; ++$i) {
$Color = imagecolorsforindex($Image,$i);
$TotalAlpha += $Color['alpha'];
}
return (($TotalAlpha/$Count) == 127) ? true : false;
}
function is_number($Str) {
$Return = true;
if ($Str < 0) { $Return = false; }
// We're converting input to a int, then string and comparing to original
$Return = ($Str == strval(intval($Str)) ? true : false);
return $Return;
}
function verysmall($Image) {
return ((imagesx($Image) * imagesy($Image)) < 25) ? true : false;
}
function image_height($Type, $Data) {
$Length = strlen($Data);
global $URL, $_GET;
switch($Type) {
case 'jpeg':
// See http://www.obrador.com/essentialjpeg/headerinfo.htm
$i = 4;
$Data = (substr($Data, $i));
$Block = unpack('nLength', $Data);
$Data = substr($Data, $Block['Length']);
$i+=$Block['Length'];
$Str []= "Started 4, + ".$Block['Length'];
while($Data!='') { // iterate through the blocks until we find the start of frame marker (FFC0)
$Block = unpack('CBlock/CType/nLength', $Data); // Get info about the block
if($Block['Block'] != '255') { break; } // We should be at the start of a new block
if($Block['Type'] != '192') { // C0
$Data = substr($Data, $Block['Length']+2); // Next block
$Str []= "Started ".$i.", + ".($Block['Length']+2);
$i+=($Block['Length']+2);
} else { // We're at the FFC0 block
$Data = substr($Data, 5); // Skip FF C0 Length(2) precision(1)
$i+=5;
$Height = unpack('nHeight', $Data);
return $Height['Height'];
}
}
break;
case 'gif':
$Data = substr($Data, 8);
$Height = unpack('vHeight', $Data);
return $Height['Height'];
case 'png':
$Data = substr($Data, 20);
$Height = unpack('NHeight', $Data);
return $Height['Height'];
default:
return 0;
}
}
function send_pm($ToID,$FromID,$Subject,$Body,$ConvID='') {
global $DB, $Cache;
if($ToID==0) {
// Don't allow users to send messages to the system
return;
}
if($ConvID=='') {
$DB->query("INSERT INTO pm_conversations(Subject) VALUES ('".$Subject."')");
$ConvID = $DB->inserted_id();
$DB->query("INSERT INTO pm_conversations_users
(UserID, ConvID, InInbox, InSentbox, SentDate, ReceivedDate, UnRead) VALUES
('$ToID', '$ConvID', '1','0','".sqltime()."', '".sqltime()."', '1')");
if ($FromID != 0) {
$DB->query("INSERT INTO pm_conversations_users
(UserID, ConvID, InInbox, InSentbox, SentDate, ReceivedDate, UnRead) VALUES
('$FromID', '$ConvID', '0','1','".sqltime()."', '".sqltime()."', '0')");
}
} else {
$DB->query("UPDATE pm_conversations_users SET
InInbox='1',
UnRead='1',
ReceivedDate='".sqltime()."'
WHERE UserID='$ToID'
AND ConvID='$ConvID'");
$DB->query("UPDATE pm_conversations_users SET
InSentbox='1',
SentDate='".sqltime()."'
WHERE UserID='$FromID'
AND ConvID='$ConvID'");
}
$DB->query("INSERT INTO pm_messages
(SenderID, ConvID, SentDate, Body) VALUES
('$FromID', '$ConvID', '".sqltime()."', '".$Body."')");
// Clear the caches of the inbox and sentbox
//$DB->query("SELECT UnRead from pm_conversations_users WHERE ConvID='$ConvID' AND UserID='$ToID'");
$DB->query("SELECT COUNT(ConvID) FROM pm_conversations_users WHERE UnRead = '1' and UserID='$ToID' AND InInbox = '1'");
list($UnRead) = $DB->next_record(MYSQLI_BOTH, FALSE);
$Cache->cache_value('inbox_new_'.$ToID, $UnRead);
//if ($UnRead == 0) {
// $Cache->increment('inbox_new_'.$ToID);
//}
return $ConvID;
}
function send_irc($Raw) {
$IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT);
fwrite($IRCSocket, $Raw);
fclose($IRCSocket);
}
require(SERVER_ROOT.'/sections/image/index.php');
?>

1
inbox.php Normal file
View File

@ -0,0 +1 @@
<? require('classes/script_start.php');

1
index.php Normal file
View File

@ -0,0 +1 @@
<? require('classes/script_start.php');

3
irc.php Normal file
View File

@ -0,0 +1,3 @@
<?
$_SERVER['SCRIPT_FILENAME'] = 'irc.php'; // PHP CLI fix
require('classes/script_start.php');

39
irc_raw.php Normal file
View File

@ -0,0 +1,39 @@
<?// This is a very primitive IRC bot
if (!isset($argv)) {
die('CLI Only.');
}
define('SERVER','irc.what.cd');
define('PORT',6667);
define('NICK','RawBot');
define('WATCH','#raw-input');
define('RELAY','#raw-output');
$Socket = fsockopen(SERVER, PORT);
fwrite($Socket, "USER ".NICK." * * :".NICK."\n");
fwrite($Socket, "NICK ".NICK."\n");
sleep(10);
fwrite($Socket, "JOIN ".WATCH."\n");
fwrite($Socket, "JOIN ".RELAY."\n");
while (!feof($Socket)) {
$Line = fgets ($Socket, 1024);
if (preg_match('/Nickname is already in use\.$/', $Line)) {
fwrite($Socket, "NICK ".NICK."_\n");
}
if (preg_match('/PING :(.+)$/', $Line, $Ping)) {
fwrite($Socket, "PONG :$Ping[1]\n");
}
// Example command
if(stripos('!mode', $Line)) {
fwrite($Socket, "PRIVMSG ".RELAY." :Mode command used\n");
fwrite($Socket, "MODE WhatMan\n");
fwrite($Socket, "WHOIS WhatMan\n");
fwrite($Socket, "MODE Orbulon\n");
}
fwrite($Socket, "PRIVMSG ".RELAY." : -----".$Line."\n");
}

3
log.php Normal file
View File

@ -0,0 +1,3 @@
<?
require 'classes/script_start.php';
?>

1
login.php Normal file
View File

@ -0,0 +1 @@
<? require('classes/script_start.php');

Some files were not shown because too many files have changed in this diff Show More