diff --git a/ABUSE b/ABUSE
new file mode 100644
index 0000000..bd11640
--- /dev/null
+++ b/ABUSE
@@ -0,0 +1,20 @@
+The following attempts to document and explain the anti-abuse system in
+TightURL. Ideally abuse is kept out of the database to begin with, but in
+many cases it must be dealt with afterward.
+
+ 1. Rejection of bad bots thanks to Bad Behavior.
+
+ 2. Rejection of invalid URLs. Since garbage in the database is abusive
+ to the operator of the TightURL service, we attempt to keep junk out.
+
+ 3. Rejection of blacklisted file extensions. Much abuse involves getting
+ someone to run a Windows executable. A set of abused extensions is
+ provided, and can be updated by the site administrator.
+
+ 4. Rejection of locally blacklisted sites.
+
+ 5. Rejection of URI blacklisted sites.
+
+ 6. Rejection of links to known redirector sites.
+
+ 7. Re-checking accepted URLs for those who run the "killbot".
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..819a2e7
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,112 @@
+v 0.1.3.3a
+October 17, 2008
+----------------
+ Bugfix: TightURL was failing to screen out forbidden extensions such as .exe
+ All users should upgrade to restore this important functionality.
+
+Feature: It is possible, if not necessarily advisable, to activate Policy Ban
+ URLs. ex: http://example.com/?ban=abc
+ This will mark the TightURL http://example.com/abc as banned for
+ violating your site's policy/Terms of Service. This feature is
+ activated by setting $pbi in tighturl.config.inc.php and is intended
+ only to allow administrators a fast and easy way to disable URLs in
+ the database. This feature will be secured in a following release
+ against misuse.
+
+v 0.1.3.3
+September 13, 2008
+------------------
+ Change: A modification has been made to the URL resolver routine to increase
+ PHP version compatibility.
+ Change: Having discovered a new class of Internet abuse, a Pay-To-Click (PTC)
+ blacklist has been added.
+ Change: Missing blacklist handling is more robust in case any are compltely
+ removed.
+ Change: Upgraded to Bad Behavior 2.0.23, which still generates one warning
+ corrected in the version distributed with TightURL.
+
+v 0.1.3.2
+July 26, 2008
+---------------
+ Bugfix: Some incorrect information in UPGRADING that referred to some work
+ in progress on the upcoming major release has been removed and
+ replaced with the correct information.
+ Change: A modification has been made to the URI blacklist lookups to try and
+ work around DNS setups that deliberately falsify returned information
+ when the true response is NXDOMAIN.
+
+v 0.1.3.1
+July 24, 2008
+---------------
+ Bugfix: Some late night last minute packaging errors resulted in an error
+ in the default local blacklist file. This has been corrected.
+ Bugfix: Another slip-up due to the late hour, the installer script creates
+ a database which begins issuing redirection URLs in the ten-thousands
+ instead of zero. This has been corrected.
+
+v 0.1.3
+July 24, 2008
+---------------
+Feature: Optional full Bad Behavior integration into TightURL front-end!
+ http://www.bad-behavior.ioerror.us/
+Feature: Option to require submitted URLs to exist.
+Feature: Resolves all submitted HTTP URLs to the end up to 10 redirects.
+ Bugfix: Strip tags embedded within
tags in tighturl.tmpl .
+Feature: New templates for blacklisted URLs, URLs that violate site policy,
+ URLs disabled due to complaints, Greylisted URLs, and previews.
+Feature: tighturl-install.php preliminary web-based installer and
+ upgrade script. Presently allows for either the initial creation of
+ the tables TightURL uses, or upgrades an existing 0.1.2 or earlier
+ database to the current schema.
+Feature: tighturl-killbot shell script partly developed to cut off service to
+ abused URLs. An attempt will be made to piggyback maintenance tasks
+ on top of service requests.
+Feature: TightURL now updates the fields status, lasthit, hits, adddate, addip.
+ These fields were added as necessary for the anti-abuse
+ system. There is no intent to add an ability to view this data
+ for its own sake, however it may later be displayed as part the
+ anti-abuse information in previews.
+Feature: Updatable urlpatterns, two-level domains pattern, redirector patterns.
+ rejecting URIs of other known redirectors.
+Feature: Blacklist domains to refuse to create TightURLs for.
+Feature: TightURL does not accept links to itself; TightURL allows an domain
+ alias to be configured for this purpose. Both the main site and the
+ alias will be recognized with or without a preceeding "www." .
+Feature: Attempt to stop use of TightURL as an obfuscation service by
+ linking to other redirectors.
+Feature: TightURL no longer accepts URLs it can't shorten.
+ Change: TightURL now returns 301 redirects instead of 302
+Feature: Blacklist Windows executables and other file extensions.
+ Change: TightURL no longer contains any OS-specific code, thus Windows
+ support should be transparent now. Reports about TightURL working or
+ not under Windows, BSD, or OS X would be appreciated.
+ Change: Replaced chkdnsrr with gethostbyname, which should work on
+ non-Unix operating systems without a replacement function.
+ Bugfix: URIBL check was slow and worse did not work. Now works and not slow.
+ BugFix: TightURL now accepts the nasty URLs Yahoo uses.
+ Bugfix: Was truncating URLs longer than 256 characters.
+ New limit on URLs is 2083 characters
+ Bugfix: Inconsistency between config.inc.php and tighturl.sql
+ (closes SF bug 1161870)
+ Bugfix: Fix PHP warnings for defined constants. (closes SF bug 1161874)
+
+v 0.1.2
+December 3, 2004
+----------------
+ Bugfix: @ was not considered valid in URLs and should be.
+ Bugfix: Local text about running an experimental service removed from main template.
+ Bugfix: Main template link to TightURL changed from /sourcecode to /project.
+Feature: Reserved IDs, and Regexes moved into tighturl.config.inc.php
+Feature: sample config file and sample templates moved to ./local directory
+Feature: Supports validation of IPv6 URLs. (not supported for URIBL lookups)
+
+v 0.1.1
+December 2, 2004
+----------------
+ Bugfix: Bad tighturl.sql file fixed
+ Bugfix: Empty database issue fixed.
+
+v 0.1
+December 2, 2004
+----------------
+Initial Alpha release.
diff --git a/DOCUMENTATION b/DOCUMENTATION
new file mode 100644
index 0000000..eba6f6b
--- /dev/null
+++ b/DOCUMENTATION
@@ -0,0 +1,10 @@
+Submitted URLs that are accepted are assigned a sequential Base-36 ID code.
+
+ http://example.com/aa (aa is the Base-36 ID)
+
+This allows for assigning the shortest ID possible.
+
+Duplicate accepted URLs will have the existing ID returned, in preference
+to always assigning the shortest URL possible.
+
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..17fdb98
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,416 @@
+ TightURL
+ Installation
+ version 0.1.3.2
+
+ Installing TightURL
+ -------------------
+
+ 1. Untar the file: tar zxvf tighturl-0.1.3.2.tar.gz or
+ unzip the file: unzip tighturl-0.1.3.2.zip
+
+ 2. Move the files in the directory to where you want to run
+ your installation of TightURL.
+
+ 3. Rename tighturl.php to index.php if desired. (highly desirable!)
+
+ 4. A. New installations should move the contents of the ./local directory
+ into the main TightURL directory.
+ B. Upgrades should review the contents of ./local and adjust existing
+ config file and templates as seen fit. Things probably won't work
+ correctly unless you modify the tighturl.config.inc in ./local with
+ your desired settings and use that.
+
+ 5. New installations should create a MySQL database and user if
+ necessary. If you don't know how, (we were all beginners once) it
+ goes something like this:
+ mysql -u root -p
+ Enter password: **********
+ mysql> create database tighturl;
+ mysql> quit
+
+ If you also need to add a MySQL user (you should never use "root"),
+ then before you quit MySQL, you should enter a command like this:
+
+ mysql> grant all on dbname.* to dbuser@localhost identified by 'pass';
+
+ substituting the name of your database for "dbname", the name of the
+ MySQL user you want to create for "dbuser", and the desired password
+ in place of "pass".
+
+ 6. Edit the config settings in tighturl.config.inc.php as needed.
+ New installs will need to change at least the MySQL database settings.
+ See 'Configuration Settings' below.
+
+ 7. Run the script: tighturl-install.php
+ When this is done, you will need to remove or rename this script
+ before your TightURL installation will work.
+
+ 8. If you can set a custom 404 page for your Web site/directory, you
+ can set it to tighturl/index.php and get shorter URLs. To take
+ advantage of this, set $FOFMethod=TRUE in tighturl.config.inc.php.
+
+ 9. Change the $svcname in tighturl.config.inc.php if desired.
+
+ 10. Edit the master site HTML template tighturl.tmpl if desired.
+ See 'TightURL Templates' below.
+
+ 11. Edit the HTML sub-templates if desired. These are:
+ A. tighturl.main.tmpl : HTML shown for your TightURL homepage
+ B. tighturl.save.tmpl : HTML shown when a URL is saved
+ C. tighturl.help.tmpl : HTML shown for Help info (may not exist yet)
+ D. tighturl.faq.tmpl : HTML shown for FAQ (may not exist yet)
+ D. tighturl.blacklist.tmpl : HTML shown for blacklisted URL submissions
+ D. tighturl.policy.tmpl : HTML shown for URL submissions that violate
+ your local policy.
+
+ See 'TightURL Templates' below for more information.
+
+ Configuration Settings
+ ----------------------
+
+ These are the configuration (variables) settings that can and should
+ be changed in tighturl.config.inc.php :
+
+ MySQL:
+ $dbhost : DNS name of your MySQL server
+ $dbuser : MySQL user name
+ $dbpass : password for MySQL user name
+ $dbname : database containing TightURL's table
+ $dbtable : name of TightURL's table
+
+ Operating modes:
+ $FOFMethod : Use 404-Method or mod_rewrite to compress TightURLs
+ 0 (FALSE) = full URL path (not compressed) TightURLs
+ 1 = 404-Method compressed TightURLs
+ 2 = mod_rewrite compressed TightURLs
+
+ URIBL variables:
+ $uribl : Array of URIBLs to check
+ $uriblurl : Array of Web sites corresponding to URIBLs checked
+
+ Text strings and style variables:
+ $svcname : One-word name for your TightURL service
+ $verbtext : One-word name for the act of tightening URLs
+ $pasttext : Past-tense name for a tightended URL
+ $tagline : "tag line" for your TightURL service
+ $headcolor : Color for the TightURL HTML header
+ $tablecolor : Color for the table the URL input field appears in
+ $copystart : 4-digit year of start of your copyright on your content.
+ defaults to current year if not given.
+
+ NEVER CHANGE SETTINGS IN tighturl.php OR YOU WILL LOSE YOUR CHANGES
+ any time you upgrade to a newer version of TightURL. Always put your
+ configuration settings in tighturl.config.inc.php where they will
+ survive upgrades. Values in tighturl.config.inc.php override the
+ defaults (garbage) in tinyurl.php .
+
+ Reserved URLs
+ -------------
+
+ Because we use Base-36 numbers as TightURL IDs, as time goes on,
+ certain desirable URLs will be issued that we might want to keep
+ for ourselves.
+
+ For instance, the letters 'faq' are well-understood around the Internet
+ to mean "Frequently Answered Questions". We might want to use the URL
+ http://example.com/faq to point to our FAQ page, rather than issue it
+ as a regular TightURL to a random visitor. Reserved URLs allow you to
+ specify Base-36 IDs that should never be issued as TightURLs.
+
+ There are two kinds of Reserved URLs. External (implicit) and Internal
+ (explicit) Reserved URLs.
+
+ External Reserved URLs:
+
+ Any URL which exists in your Web space will be served up by
+ your Web server, and not TightURL. For this reason, any URL
+ reasonably within your TightURL ID space that you want to use
+ with your TightURL site itself should be reserved so that you
+ don't issue a TightURL to anyone that won't actually work.
+
+ For example, if you have a directory named: /www/example.com/faq
+ your Web server will attempt to serve index.html from within
+ that directory, and TightURL will never even see the request.
+ This kind of reservation is implicit, and TightURL must be
+ made aware of it.
+
+ Internal Reserved URLs:
+
+ Any URL which does not exist in your Web space but is Reserved
+ within TightURL will cause TightURL to look for a correspondingly
+ named TightURL Template, and serve that. If the template does
+ not exist, a 404 error is generated.
+
+ For example, if you have reserved the ID 'faq', and TightURL
+ sees a request for this reserved ID, it will attempt to open a
+ template named tighturl.faq.tmpl and return that to the browser.
+
+ It is VERY IMPORTANT that you decide what your Reserved URLs will be
+ before your TightURL service is put into operation, or else you run
+ the risk of wanting to reserve a URL that's already been issued as
+ a TightURL to someone. For example, by the time you've issued your
+ 19826th TightURL, you will have lost the opportunity to use 'faq' as
+ a Reserved URL, because decimal (Base-10) number '19826' is number
+ 'faq' in sexigesimal (Base-36).
+
+ Reserving URLs:
+
+ To reserve a URL, add it to the configuration array $ReservedURL .
+ The following URLs are reserved by default:
+
+ faq, help, code, source, docs, cvs, arch, url,
+ about, admin, setup, svn
+
+ There is little point in reserving URLs larger than 5 charcters long.
+ The first 6 character ID is '100000' sexigesimal, which would be far
+ past your 60 millionth TightURL issued. Since each additional Reserved
+ URL adds a little more processing time, you don't want to add URLs
+ that will never be issued anyway.
+
+ TightURL presently uses the ID "api" with the template that describes
+ how to use the TightURL API. It would be the 13878th TightURL in the
+ system, which can easily be achieved on a moderately-used corporate-
+ wide TightURL installation.
+
+ TightURL Templates
+ ------------------
+ TightURL supports a simple variable-substitution templating system with
+ one level of template nesting.
+
+ The outer template is *always* the main site template, tighturl.tmpl .
+ This template controls your site design and is *always* used to generate
+ output pages to the browser.
+
+ The inner template is *always* one of the following sub-templates
+ (or no sub-template):
+ tighturl.main.tmpl : HTML shown for your TightURL homepage
+ tighturl.save.tmpl : HTML shown when a URL is saved
+ tighturl.help.tmpl : HTML shown for Help info (may not exist yet)
+ (none) : No inner template.
+
+ Please note that many screens are generated using only the main site
+ (outer) template. All error screens are generated this way.
+
+ The variables supported by TightURL Templates are:
+
+ $HTML : In the innermost or only template, replaced by a HTML
+ message from TightURL. In an outer template, it is
+ replaced by contents of the inner (sub-)template.
+ You should never remove this variable from a template.
+ $PARM : Parameter when 404-Method not used.
+ $URL : Replaced by browser submitted URL.
+ $URLLEN : Replaced by lenghth of the submitted URL.
+ $TIGHTURL : Replaced by TightURL generated by the submission.
+ $TIGHTURLLEN : Replaced by length of the generated TightURL.
+ $DIFF : Replaced by difference in length between URLs.
+ $INPUT : Replaced by submitted URL for use when there has
+ been an error detected in the input.
+ $SVCNAME : Replaced by name chosen for your TightURL service.
+ $HEADCOLOR : Replaced by color value chosen for HTML tags.
+ $TABLECOLOR : Replaced by color value chosen for the table.
+ $TAGLINE : Replaced by "tag line" for your TightURL service.
+ $CPASTTEXT : Replaced by capitalized past tense description of
+ tightened URLs.
+ $PASTTEXT : Same as $CPASTTEXT, but first letter not capitalized.
+ $CVERBTEXT : Replaced by capitalized verb description of your
+ TightURL service.
+ $VERBTEXT : Same as $CVERBTEXT, but first letter not capitalized.
+ $COPYRIGHT : Replaced by generated copyright string created from
+ $copystart config value and current year.
+ $URIBLS : Replaced by HTML showing URIBLs being checked.
+ $HOST : Replaced by hostname of Web site.
+ $SELF : Replaced by the URL path to the TightURL script.
+ $BBSTATS : Replaced by Bad Behavior stats when BB2 is enabled.
+ $TIGHTURLVER : Replaced by the TightURL running version number.
+
+ TightURL Operating Modes
+ ------------------------
+
+ TightURL supports three distinct "operating modes". These are known as
+ "basic", "mod_rewrite", and "404 Method". You want to avoid changing your
+ operating mode later, as changes to or from basic mode will cause all your
+ URLs to change. Changes between mod_rewrite and the 404 Method do not
+ result in changes to your URLs, but your operating mode is something you
+ should choose carefully and then stick with.
+
+ Using basic mode
+ ----------------
+
+ This operating mode produces URLs that follow this pattern:
+ http://example.com/?i=id or http://example.com/yoursite/?i=id
+
+ No changes to httpd.conf or .htaccess are required for basic mode, but
+ this produces slightly longer and more inconvenient to type URLs. If you
+ can use mod_rewrite or the 404 Method, it is highly recommended that you
+ do so.
+
+
+ Using mod_rewrite with Apache
+ -----------------------------
+
+ PLEASE NOTE: There was a longstanding bug in Apache mod_rewrite that
+ probably makes TightURL or anything like it unable to work except with
+ what are still very recent versions of Apache.
+ https://issues.apache.org/bugzilla/show_bug.cgi?id=34602
+
+ Users are encouraged to use "404 Mode", and especially in the event
+ their Apache version has the bug shown above.
+
+
+ This operating mode produces URLs that follow this pattern:
+ http://example.com/id or http://example.com/yoursite/id
+
+ TightURL can be used with mod_rewrite by adding the following lines to
+ httpd.conf or if you can't modify httpd.conf, you can use .htaccess :
+
+
+ RewriteEngine On
+ RewriteRule ^view/([a-z0-9-]+)/?$ index.php?v=$1 [NC,L]
+ RewriteRule ^([a-z0-9-]+)/?$ index.php?i=$1 [NC,L]
+
+
+ If you change the parameters (form variables) from "i" for the TightURL ID
+ to look up, and "v" for the TightURL ID to preview, then you'll need to
+ adjust these lines accordingly.
+
+ Be aware that http.conf is read once when the Web server is started or
+ reloaded, but .htaccess must be read and parsed for *every request*, so
+ you always want to use http.conf over .htaccess whenever possible.
+
+
+ Using "The 404-Method" with Apache
+ ----------------------------------
+
+ This operating mode produces URLs that follow this pattern:
+ http://example.com/id or http://example.com/yoursite/id
+
+ The "404-Method" refers to instructing your Web server to direct all
+ requests that generate a "Not found" error (which is an HTTP error code
+ 404) to the TightURL script. By doing this, TightURL will run for URLs in
+ your TightURL site that don't exist, such as would be the case for
+ http://example.com/tighturl.php/xxyy
+
+ The xxyy is a TightURL ID number, not an actual Web page in your site. By
+ sending non-existent page requests to the TightURL script, you can look up
+ those IDs and issue an HTTP Redirect without the need for mod_rewrite.
+
+ To use the 404-Method, set $FOFMethod=1 in tighturl.config.inc.php.
+
+ Using .htaccess
+ ---------------
+
+ Then put this in your .htaccess file:
+
+ ErrorDocument 404 /index.php
+
+ This change should take effect immediately after saving .htaccess .
+ If it doesn't work, make sure you have AllowOverride FileInfo on in the
+ directory you're running TightURL from.
+
+ Using httpd.conf
+ ----------------
+
+ Alternatively to using .htaccess (and for improved performance), put the
+ following line in your httpd.conf in the appropriate Directory section
+ (and VirtualHost if applicable):
+
+ ErrorDocument 404 /index.php
+
+ You will need to reload your Apache configuration for this change to take
+ effect.
+
+ See the Apache documentation for more information.
+ http://httpd.apache.org/docs/mod/core.html#errordocument
+ http://httpd.apache.org/docs/mod/core.html#allowoverride
+
+
+ AntiAbuse: Generally if your web site is connected to the Internet and
+ and the TightURL library can make outbound network connections, you should
+ run with the antiabuse system turned on. When the antiabuse system is
+ turned off, virtually everything will be accepted into your database that
+ can be shortened.
+
+ NetChecks: Generally if your web site is connected to the Internet and
+ and the TightURL library can make outbound network connections, you should
+ run with the netchecks system turned on. If your site has no connectivity
+ or ability to make outbound network connections, you should turn the
+ netchecks off. When netchecks are off, TightURL will not be able to resolve
+ URLs through redirections to their final destination, check for new versions
+ of TightURL, or check submitted URLs against URI blacklists.
+
+
+ Adding more URIBLs
+ ------------------
+
+ In the event other URIBLs beside SURBL become available, and you wish
+ to check those also, edit $uribl and $uriblurl in
+ tighturl.config.inc.php .
+
+ To add a new URIBL named uribl.example.com whose Web site is located
+ at http://www.example.com
+
+ Change this:
+
+ $uribl = array("multi.surbl.org");
+ $uriblurl = array("www.surbl.org");
+
+ To this:
+
+ $uribl = array("multi.surbl.org","uribl.example.com");
+ $uriblurl = array("www.surbl.org","www.example.com");
+
+ You can add as many URIBLs as you want this way.
+
+ Squeezing Your Base URL Down to the Smallest Possible Size
+ ----------------------------------------------------------
+ The "base URL" is the fixed portion of your TightURL URLs. This
+ would be everything up to the TightURL ID at the end of the URL.
+ The length of the TightURL ID will start out at 1 character and may
+ get up to 6 characters after tens of millions of TightURLs have been
+ created in your system. (Most TightURL installations are not
+ expected to get into the tens of thousands, let alone tens of
+ millions) Because the ID is at most 6 characters, the most
+ important thing you can do to get the shortest URL possible is to
+ "squeeze" as many characters out of the base portion of the URL
+ as possible.
+
+ The following URL is "unfortunately long", but should still allow
+ you to create tens of millions of TightURLs that can be used without
+ wrapping in most e-mail programs. It is 72 characters long:
+
+ http://www.a-really-quite-long-name.com/~example01/tighturl.php?i=abcdef
+
+ This URL is not only unfortunately long, it is unnecessarily long
+ as well. The following optimizations can be attempted:
+
+ 1. Drop the "www."
+ 2. Rename tighturl.php to something shorter.
+ 3. Rename tighturl.php to index.php and put it in a 1-character subdir.
+
+ If optimizations 1 and 3 are successfully applied, we get a 58
+ character URL (14 characters shorter):
+
+ http://a-really-quite-long-name.com/~example01/t/?i=abcdef
+
+ A more optimistic domain name (39 characters):
+
+ http://example.com/~example/t/?i=abcdef
+
+ Ideal scenario with own domain (29 characters):
+
+ http://tighturl.com/?i=abcdef
+
+ If you are able to use Mod_Rewrite or the 404-Method as shown
+ above, you can also drop the "?i=" portion of the URL, saving
+ another 3 characters.
+
+ Mod_Rewrite or 404-Method scenario (26 characters):
+
+ http://tighturl.com/abcdef
+
+ This also works with the "unfortunately long" URL, bringing
+ it down to 56 characters:
+
+ http://a-really-quite-long-name.com/~example01/t/abcdef
+
+********************************************************************************
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..14db8fc
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice 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 Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under 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:
+
+ a) 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,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, 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,
+
+ c) 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 program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies 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 published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..56e201a
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,15 @@
+NEWS
+====
+
+This is a quick release of the version in use at http://tighturl.com
+due to some user requests and the need to spend more time working on
+the next major release. It contains an all new installer, bugfixes,
+and some important new functionality backported from the development
+version.
+
+There's likely to be some unused templates.
+
+**** First time TightURL users who installed 0.1.3 should delete and
+then recreate their database, then install this version and re-run
+the installer script to avoid generating needlessly large URLs.
+Everyone else should follow the normal instructions.
diff --git a/README b/README
new file mode 100644
index 0000000..6f43b19
--- /dev/null
+++ b/README
@@ -0,0 +1,155 @@
+
+ TightURL
+ Version 0.1.3.2
+
+ What is it?
+ -----------
+
+ TightURL is a LAMP-based (Linux Apache MySQL PHP) blind redirection
+ service similar to TinyURL, designed for personal or company use by
+ those who prefer not to use external services, or cannot use them for
+ legal or logistical reasons. It may run correctly on a WAMP server
+ (Windows Apache MySQL PHP), but it is unknown if it does or not.
+
+ The major consideration in the design was the ability to customize
+ the application without altering program code. All browser output
+ except fatal error messages is produced by HTML-based templates.
+
+ A fair amount of customization is possible simply by setting a few
+ configuration variables in the configuration file or editing the
+ included HTML template files. Under no circumstances does the program
+ script file ever have to be edited, unless you're a developer.
+
+ The primary reason for a blind redirection service is to avoid
+ e-mailing URLs to people that are broken when received, because the
+ recipient's e-mail program is unable to pick up the rest of the URL
+ after a line-wrap. It is called a blind redirection service because
+ you can't tell where you'll end up just by looking at the link.
+
+ For the purposes of TightURL, we want to generate the shortest
+ redirection URL possible, thus we use a blind redirection URL, and
+ encourage the use of mod_rewrite or the "404-page Method" to achieve
+ the shortest possible URL.
+
+ Can I use it without getting a special domain for it?
+ -----------------------------------------------------
+ Yes. The requirement for TightURL to be considered useful is the
+ ability is to create a URL that won't wrap in a plain text e-mail
+ message. That means the upper limit is about 72 characters of URL.
+ A worst case scenario looks like this:
+
+ http://www.a-really-quite-long-name.com/~example01/tighturl.php?i=abcdef
+
+ Even this example can actually be made 10 characters shorter in most
+ cases without needing to ask the webmaster for special settings:
+
+ http://www.a-really-quite-long-name.com/~example01/t/?i=abcdef
+
+ See INSTALL for more details on how to "squeeze" your base URL down
+ to the smallest possible size.
+
+ Why was it written?
+ -------------------
+
+ This software was written for the oldest reason in the Free Software
+ book; to scratch an itch. The author had been looking for some
+ Free Software to run his own URL shortening service. Finding no Free
+ Software that fit the bill, and wanting a first PHP project to work
+ on, TightURL was born. Issuing an HTTP Redirect is not exactly
+ rocket science, what the URL shortening service is really providing
+ is convenience and processing resources.
+
+ The software itself can be boiled down to a very few lines if it is
+ hard-wired to its configuration values and output screens. But
+ since the author had been looking for some cookie-cutter software and
+ couldn't find any, he decided to write this so that hopefully no one
+ else will have to. It can be cosmetically tweaked from the config
+ file very easily, and in more depth by editing the HTML templates.
+
+
+ Additional Disclaimer
+ ---------------------
+
+ Original author's code sucks. He is a rank amateur, evertything a
+ professional developer despises. (I wouldn't run code written by me
+ if I were you.)
+
+ Contributing (code) to TightURL
+ -------------------------------
+
+ Patches welcome. Critical advice welcomed if gently given.
+ Access to CVS or Arch possible, please contact maintainer.
+ ron-a-t-vnetworx.net
+
+ The Latest Version
+ ------------------
+
+ Details about the latest stable and development versions are
+ available at the TightURL Web site at http://tighturl.com/ .
+
+ Documentation
+ -------------
+
+ The documentation available as of the date of this release is the
+ contents of this README file. Additional documentation is available
+ at runtime in the browser for using TightURL.
+
+ Requirements
+ ------------
+
+ PHP - Should work with any version >= 4.3.0
+ MySQL - Should work with versions greater than >= 3.x
+
+ Features
+ --------
+
+ * Can create very short URLs using mod_rewrite or the "404 Method"
+ * ID size kept very short by using Base-36 IDs
+ * The same URL entered more than once always returns the same ID
+ * All output is generated by templates.
+ * Site design is controlled by a single template.
+
+ Known Limitations
+ -----------------
+
+ TightURL probably works under Windows with Apache and MySQL, but we
+ have no way of knowing for sure until someone reports they've tested it
+ and it works. One possible problem would be if TightURL can't find
+ nslookup on the PATH. The Windows version uses nslookup as a kluge for
+ missing functionality in PHP for Windows.
+
+ Coming Features
+ ---------------
+
+ Please see the file called TODO.
+
+ Installation
+ ------------
+
+ Please see the file called INSTALL for detailed installation
+ instructions.
+
+ Anti-spam Features
+ ------------------
+
+ A problem with blind redirection services is they can be abused by
+ spammers to conceal the domains their spam is trying to get people to visit.
+ The TightURL Library attempts to screen out other known redirection
+ services, Windows executables, and matches against your local blacklist.
+
+ To keep spammers and phishers from abusing TightURL, it checks the URI
+ blacklists at multi.surbl.org and black.uribl.com . TightURL will refuse to
+ add URLs that appear on these URI BLs. You can add additional URI BLs.
+
+ Licensing
+ ---------
+
+ Please see the file called LICENSE.
+
+ Acknowledgments
+ ----------------
+
+ The TightURL developer(s) acknowledge the following copyrighted works
+ that make up portions of the TightURL software:
+
+ Bad Behavior
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..d2a221f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,8 @@
+Bugs:
+=====
+All known bugs in the released versions have been fixed.
+
+API:
+====
+The API has not been implemented, and may not be as it seems to be little
+more than an abuse vector.
diff --git a/UPGRADING b/UPGRADING
new file mode 100644
index 0000000..2fa89a5
--- /dev/null
+++ b/UPGRADING
@@ -0,0 +1,25 @@
+Upgrading TightURL
+==================
+
+Please note that those using nightly builds of TightURL may end up with cruft
+in their databases. Upgrades are designed to work with released versions.
+
+There have been many additions to the configuration file. You may wish to
+review the sample tighturl.config. You should also compare your templates
+against the ones in this version of TightURL if you've customized your
+templates.
+
+Current users of versions 0.1.3.1
+---------------------------------
+Your database is current. No need to run tighturl-install.php .
+
+Current users of version 0.1.3
+------------------------------
+Users upgrading from the (broken) 0.1.3 release should delete their empty
+database, recreate it, and run tighturl-install.php again.
+
+Current users of versions prior to 0.1.3
+----------------------------------------
+Users upgrading from versions prior to 0.1.3 should run the installer
+script, tighturl-install.php in order to upgrade their database to the latest
+version.
diff --git a/bad-behavior/COPYING b/bad-behavior/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/bad-behavior/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice 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 Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under 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:
+
+ a) 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,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, 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,
+
+ c) 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 program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies 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 published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/bad-behavior/README.txt b/bad-behavior/README.txt
new file mode 100644
index 0000000..c7dbc42
--- /dev/null
+++ b/bad-behavior/README.txt
@@ -0,0 +1,102 @@
+=== Bad Behavior ===
+Tags: comment,trackback,referrer,spam,robot,antispam
+Contributors: error, MarkJaquith, Firas, skeltoac
+Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=error%40ioerror%2eus&item_name=Bad%20Behavior%20%28From%20WordPress%20Page%29&no_shipping=1&cn=Comments%20about%20Bad%20Behavior&tax=0¤cy_code=USD&bn=PP%2dDonationsBF&charset=UTF%2d8
+Requires at least: 1.2
+Tested up to: 2.7
+Stable tag: 2.0.23
+
+Welcome to a whole new way of keeping your blog, forum, guestbook, wiki or
+content management system free of link spam. Bad Behavior is a PHP-based
+solution for blocking link spam and the robots which deliver it.
+
+Bad Behavior complements other link spam solutions by acting as a gatekeeper,
+preventing spammers from ever delivering their junk, and in many cases, from
+ever reading your site in the first place. This keeps your site's load down,
+makes your site logs cleaner, and can help prevent denial of service
+conditions caused by spammers.
+
+Bad Behavior also transcends other link spam solutions by working in a
+completely different, unique way. Instead of merely looking at the content of
+potential spam, Bad Behavior analyzes the delivery method as well as the
+software the spammer is using. In this way, Bad Behavior can stop spam attacks
+even when nobody has ever seen the particular spam before.
+
+Bad Behavior is designed to work alongside existing spam prevention services
+to increase their effectiveness and efficiency. Whenever possible, you should
+run it in combination with a more traditional spam prevention service.
+
+Bad Behavior works on, or can be adapted to, virtually any PHP-based Web
+software package. Bad Behavior is available natively for WordPress, MediaWiki,
+Drupal, ExpressionEngine, and LifeType, and people have successfully made it
+work with Movable Type, phpBB, and many other packages.
+
+Installing and configuring Bad Behavior on most platforms is simple and takes
+only a few minutes. In most cases, no configuration at all is needed. Simply
+turn it on and stop worrying about spam!
+
+The core of Bad Behavior is free software released under the GNU General
+Public License. (On some non-free platforms, special license terms exist for
+Bad Behavior's platform connector.)
+
+== Installation ==
+
+*Warning*: If you are upgrading from a 1.x.x version of Bad Behavior,
+you must remove it from your system entirely, and delete all of its
+database tables, before installing Bad Behavior 2.0.x. You do not need
+to remove a 2.0.x version of Bad Behavior before upgrading to this
+release.
+
+Bad Behavior has been designed to install on each host software in the
+manner most appropriate to each platform. It's usually sufficient to
+follow the generic instructions for installing any plugin or extension
+for your host software.
+
+On MediaWiki, it is necessary to add a second line to LocalSettings.php
+when installing the extension. Your LocalSettings.php should include
+the following:
+
+` include_once( 'includes/DatabaseFunctions.php' );
+ include( './extensions/Bad-Behavior/bad-behavior-mediawiki.php' );
+
+For complete documentation and installation instructions, please visit
+http://www.bad-behavior.ioerror.us/
+
+== Release Notes ==
+
+= Bad Behavior 2.0 Known Issues =
+
+* Bad Behavior may be unable to protect cached pages on MediaWiki.
+
+* When upgrading from version 2.0.19 or prior on MediaWiki and WordPress,
+you must remove the old version of Bad Behavior from your system manually
+before manually installing the new version. Other platforms are not
+affected by this issue.
+
+* The basic functionality of Bad Behavior on WordPress requires version 1.2
+or later. The management page for WordPress, which allows browsing Bad
+Behavior's logs, requires version 2.1 or later. Users of older versions should
+use phpMyAdmin to browse Bad Behavior's logs, or upgrade WordPress.
+
+* On WordPress when using WordPress Advanced Cache (WP-Cache) or WP-Super
+Cache, Bad Behavior requires a patch to WP-Cache or WP-Super Cache in order to
+protect Cached pages. Bad Behavior cannot protect Super Cached pages.
+
+ Edit the wp-content/plugins/wp-cache/wp-cache-phase1.php or
+wp-content/plugins/wp-super-cache/wp-cache-phase1.php file and find the
+following two lines at around line 34 (line 56 in WP-Super Cache):
+
+` if (! ($meta = unserialize(@file_get_contents($meta_pathname))) )
+ return;`
+
+ Immediately after this, insert the following line:
+
+` require_once( ABSPATH . 'wp-content/plugins/Bad-Behavior/bad-behavior-generic.php');`
+
+ Then visit your site. Everything should work normally, but spammers will
+not be able to access your cached pages either.
+
+* When using Bad Behavior in conjunction with Spam Karma 2, you may see PHP
+warnings when Spam Karma 2 displays its internally generated CAPTCHA. This
+is a design problem in Spam Karma 2. Contact the author of Spam Karma 2 for
+a fix.
diff --git a/bad-behavior/bad-behavior-generic.php b/bad-behavior/bad-behavior-generic.php
new file mode 100644
index 0000000..7558c5a
--- /dev/null
+++ b/bad-behavior/bad-behavior-generic.php
@@ -0,0 +1,144 @@
+ 'bad_behavior',
+ 'display_stats' => true,
+ 'strict' => false,
+ 'verbose' => false,
+ 'logging' => true,
+ 'httpbl_key' => '',
+ 'httpbl_threat' => '25',
+ 'httpbl_maxage' => '30',
+);
+
+// Bad Behavior callback functions.
+
+// Return current time in the format preferred by your database.
+function bb2_db_date() {
+ return gmdate('Y-m-d H:i:s'); // Example is MySQL format
+}
+
+// Return affected rows from most recent query.
+function bb2_db_affected_rows() {
+ return false;
+}
+
+// Escape a string for database usage
+function bb2_db_escape($string) {
+ // return mysql_real_escape_string($string);
+ return $string; // No-op when database not in use.
+}
+
+// Return the number of rows in a particular query.
+function bb2_db_num_rows($result) {
+ if ($result !== FALSE)
+ return count($result);
+ return 0;
+}
+
+// Run a query and return the results, if any.
+// Should return FALSE if an error occurred.
+// Bad Behavior will use the return value here in other callbacks.
+function bb2_db_query($query) {
+ return FALSE;
+}
+
+// Return all rows in a particular query.
+// Should contain an array of all rows generated by calling mysql_fetch_assoc()
+// or equivalent and appending the result of each call to an array.
+function bb2_db_rows($result) {
+ return $result;
+}
+
+// Return emergency contact email address.
+function bb2_email() {
+ // return "example@example.com"; // You need to change this.
+ return "badbots@ioerror.us"; // You need to change this.
+}
+
+// retrieve settings from database
+// Settings are hard-coded for non-database use
+function bb2_read_settings() {
+ global $bb2_settings_defaults;
+ return $bb2_settings_defaults;
+}
+
+// write settings to database
+function bb2_write_settings($settings) {
+ return false;
+}
+
+// installation
+function bb2_install() {
+ return false;
+}
+
+// Screener
+// Insert this into the section of your HTML through a template call
+// or whatever is appropriate. This is optional we'll fall back to cookies
+// if you don't use it.
+function bb2_insert_head() {
+ global $bb2_javascript;
+ echo $bb2_javascript;
+}
+
+// Display stats? This is optional.
+function bb2_insert_stats($force = false) {
+ $settings = bb2_read_settings();
+
+ if ($force || $settings['display_stats']) {
+ $blocked = bb2_db_query("SELECT COUNT(*) FROM " . $settings['log_table'] . " WHERE `key` NOT LIKE '00000000'");
+ if ($blocked !== FALSE) {
+ echo sprintf('%1$s %2$s %3$s %4$s
', __('Bad Behavior'), __('has blocked'), $blocked[0]["COUNT(*)"], __('access attempts in the last 7 days.'));
+ }
+ }
+}
+
+// Return the top-level relative path of wherever we are (for cookies)
+// You should provide in $url the top-level URL for your site.
+function bb2_relative_path() {
+ //$url = parse_url(get_bloginfo('url'));
+ //return $url['path'] . '/';
+ return '/';
+}
+
+// Calls inward to Bad Behavor itself.
+require_once(BB2_CWD . "/bad-behavior/version.inc.php");
+require_once(BB2_CWD . "/bad-behavior/core.inc.php");
+bb2_install(); // FIXME: see above
+
+bb2_start(bb2_read_settings());
+
+?>
diff --git a/bad-behavior/bad-behavior-lifetype.php b/bad-behavior/bad-behavior-lifetype.php
new file mode 100644
index 0000000..3ca270f
--- /dev/null
+++ b/bad-behavior/bad-behavior-lifetype.php
@@ -0,0 +1,172 @@
+Affected_Rows();
+ }
+
+ // Escape a string for database usage
+ function bb2_db_escape($string) {
+ lt_include( PLOG_CLASS_PATH."class/database/db.class.php" );
+
+ return Db::qstr($string);
+ }
+
+ // Return the number of rows in a particular query.
+ function bb2_db_num_rows($result) {
+ return $result->RecordCount();
+ }
+
+ // Run a query and return the results, if any.
+ // Should return FALSE if an error occurred.
+ function bb2_db_query($query) {
+ lt_include( PLOG_CLASS_PATH."class/database/db.class.php" );
+ $db =& Db::getDb();
+
+ $result = $db->Execute( $query );
+
+ if (!$result)
+ return FALSE;
+
+ return $result;
+ }
+
+ // Return all rows in a particular query.
+ // Should contain an array of all rows generated by calling mysql_fetch_assoc()
+ // or equivalent and appending the result of each call to an array.
+ function bb2_db_rows($result) {
+ $rows = array();
+ while( $row = $result->FetchRow()) {
+ $rows[] = $row;
+ }
+
+ return $rows;
+ }
+
+ // Return emergency contact email address.
+ function bb2_email() {
+ return BB2_EMERGENCY_EMAIL;
+ }
+
+ // retrieve settings from lifetype config
+ function bb2_read_settings() {
+ lt_include( PLOG_CLASS_PATH."class/database/db.class.php" );
+ lt_include( PLOG_CLASS_PATH."class/config/config.class.php" );
+ $config =& Config::getConfig();
+ $prefix = Db::getPrefix();
+ $logTable = $config->getValue( 'bb2_log_table', BB2_DEFAULT_LOG_TABLE );
+ $displayStats = $config->getValue( 'bb2_display_stats', true );
+ $strict = $config->getValue( 'bb2_strict', false );
+ $verbose = $config->getValue( 'bb2_verbose', false );
+ $isInstalled = $config->getValue( 'bb2_installed', false );
+ $logging = $config->getValue( 'bb2_logging', true );
+ $httpbl_key = $config->getValue( 'bb2_httpbl_key', '' );
+ $httpbl_threat = $config->getValue( 'bb2_httpbl_threat', '25' );
+ $httpbl_maxage = $config->getValue( 'bb2_httpbl_maxage', '30' );
+
+ return array('log_table' => $prefix . $logTable,
+ 'display_stats' => $displayStats,
+ 'strict' => $strict,
+ 'verbose' => $verbose,
+ 'logging' => $logging,
+ 'httpbl_key' => $httpbl_key,
+ 'httpbl_threat' => $httpbl_threat,
+ 'httpbl_maxage' => $httpbl_maxage,
+ 'is_installed' => $isInstalled );
+ }
+
+ // write settings to lifetype config
+ function bb2_write_settings($settings) {
+ lt_include( PLOG_CLASS_PATH."class/config/config.class.php" );
+ $config =& Config::getConfig();
+ $config->setValue( 'bb2_log_table', BB2_DEFAULT_LOG_TABLE );
+ $config->setValue( 'bb2_display_stats', $settings['display_stats'] );
+ $config->setValue( 'bb2_strict', $settings['strict'] );
+ $config->setValue( 'bb2_verbose', $settings['verbose'] );
+ $config->setValue( 'bb2_httpbl_key', $settings['httpbl_key'] );
+ $config->setValue( 'bb2_httpbl_threat', $settings['httpbl_threat'] );
+ $config->setValue( 'bb2_httpbl_maxage', $settings['httpbl_maxage'] );
+ $config->setValue( 'bb2_installed', $settings['is_installed'] );
+ $config->save();
+ }
+
+ // installation
+ function bb2_install() {
+ $settings = bb2_read_settings();
+ if( $settings['is_installed'] == false && $settings['logging'] )
+ {
+ bb2_db_query(bb2_table_structure($settings['log_table']));
+ $settings['is_installed'] = true;
+ bb2_write_settings( $settings );
+ }
+ }
+
+ // Return the top-level relative path of wherever we are (for cookies)
+ function bb2_relative_path() {
+ lt_include( PLOG_CLASS_PATH."class/config/config.class.php" );
+ $config =& Config::getConfig();
+
+ $url = parse_url( $config->getValue( 'base_url' ) );
+ if( empty($url['path']) )
+ return '/';
+ else {
+ if( substr( $url['path'], -1, 1 ) == '/' )
+ return $url['path'];
+ else
+ return $url['path'] . '/';
+ }
+ }
+
+ // Load Bad Behavior Core
+ lt_include(BB2_CWD . "bad-behavior/core.inc.php");
+ bb2_install();
+ $settings = bb2_read_settings();
+ bb2_start($settings);
+
+ // Time Stop
+ $bb2_mtime = explode(" ", microtime());
+ $bb2_timer_stop = $bb2_mtime[1] + $bb2_mtime[0];
+ $bb2_timer_total = $bb2_timer_stop - $bb2_timer_start;
+?>
diff --git a/bad-behavior/bad-behavior-mediawiki.php b/bad-behavior/bad-behavior-mediawiki.php
new file mode 100644
index 0000000..c47d58b
--- /dev/null
+++ b/bad-behavior/bad-behavior-mediawiki.php
@@ -0,0 +1,160 @@
+ $wgDBprefix . 'bad_behavior',
+ 'display_stats' => true,
+ 'strict' => false,
+ 'verbose' => false,
+ 'logging' => true,
+ 'httpbl_key' => '',
+ 'httpbl_threat' => '25',
+ 'httpbl_maxage' => '30',
+);
+
+define('BB2_CWD', dirname(__FILE__));
+
+// Bad Behavior callback functions.
+
+// Return current time in the format preferred by your database.
+function bb2_db_date() {
+ return gmdate('Y-m-d H:i:s');
+}
+
+// Return affected rows from most recent query.
+function bb2_db_affected_rows($result) {
+ return wfAffectedRows($result);
+}
+
+// Escape a string for database usage
+function bb2_db_escape($string) {
+ // FIXME SECURITY: Get a straight answer from somebody on how MW escapes stuff
+ return addslashes($string);
+}
+
+// Return the number of rows in a particular query.
+function bb2_db_num_rows($result) {
+ return wfNumRows($result);
+}
+
+// Run a query and return the results, if any.
+// Should return FALSE if an error occurred.
+function bb2_db_query($query) {
+ $bb2_last_query = wfQuery($query, DB_WRITE);
+ return $bb2_last_query;
+}
+
+// Return all rows in a particular query.
+// Should contain an array of all rows generated by calling mysql_fetch_assoc()
+// or equivalent and appending the result of each call to an array.
+function bb2_db_rows($result) {
+ $rows = array();
+ while ($row = wfFetchRow($result)) {
+ $rows[] = $row;
+ }
+ return $rows;
+}
+
+// Return emergency contact email address.
+function bb2_email() {
+ global $wgEmergencyContact;
+ return $wgEmergencyContact;
+}
+
+// This Bad Behavior-related function is a stub. You can help MediaWiki by expanding it.
+// retrieve settings from database
+function bb2_read_settings() {
+ global $bb2_settings_defaults;
+ return $bb2_settings_defaults;
+}
+
+// This Bad Behavior-related function is a stub. You can help MediaWiki by expanding it.
+// write settings to database
+function bb2_write_settings($settings) {
+ return;
+}
+
+// In some configurations automatic table creation may fail with the message
+// You must update your load-balancing configuration.
+// You can create the table manually (see query in
+// bad-behavior/database.inc.php) and add this line to your LocalSettings.php:
+//
+// define('BB2_NO_CREATE', true);
+
+// installation
+function bb2_install() {
+ $settings = bb2_read_settings();
+ if (defined('BB2_NO_CREATE')) return;
+ if (!$settings['logging']) return;
+ bb2_db_query(bb2_table_structure($settings['log_table']));
+}
+
+// Return the top-level relative path of wherever we are (for cookies)
+function bb2_relative_path() {
+ // TODO: This might not be the best way, but it seems to work
+ global $wgScript;
+ return dirname($wgScript) . "/";
+}
+
+// Cute timer display
+function bb2_mediawiki_timer(&$parser, &$text) {
+ global $bb2_timer_total;
+ $text = "" . $text;
+ return true;
+}
+
+function bb2_mediawiki_entry() {
+ global $bb2_timer_total;
+
+ $bb2_mtime = explode(" ", microtime());
+ $bb2_timer_start = $bb2_mtime[1] + $bb2_mtime[0];
+
+ if (php_sapi_name() != 'cli') {
+ require_once(BB2_CWD . "/bad-behavior/core.inc.php");
+ bb2_install(); // FIXME: see above
+ $settings = bb2_read_settings();
+ bb2_start($settings);
+ }
+
+ $bb2_mtime = explode(" ", microtime());
+ $bb2_timer_stop = $bb2_mtime[1] + $bb2_mtime[0];
+ $bb2_timer_total = $bb2_timer_stop - $bb2_timer_start;
+}
+
+require_once(BB2_CWD . "/bad-behavior/version.inc.php");
+$wgExtensionCredits['other'][] = array(
+ 'name' => 'Bad Behavior',
+ 'version' => BB2_VERSION,
+ 'author' => 'Michael Hampton',
+ 'description' => 'Detects and blocks unwanted Web accesses',
+ 'url' => 'http://www.bad-behavior.ioerror.us/'
+);
+
+#$wgHooks['ParserAfterTidy'][] = 'bb2_mediawiki_timer';
+$wgExtensionFunctions[] = 'bb2_mediawiki_entry';
+
+?>
diff --git a/bad-behavior/bad-behavior-tighturl.php b/bad-behavior/bad-behavior-tighturl.php
new file mode 100644
index 0000000..21bd034
--- /dev/null
+++ b/bad-behavior/bad-behavior-tighturl.php
@@ -0,0 +1,166 @@
+
+
+I wrote almost none of this, but if you're using this file, you should contact
+me (Ron Guerin) and not Michael Hampton, the author of Bad Behavior if you
+have questions about this file or the installation of Bad Behavior that you
+got with TightURL (which has been modified so as to not throw some unneeded
+warnings).
+
+Based on bad-behavior-generic.php
+Copyright (C) 2005-2006 Michael Hampton badbots AT ioerror DOT us
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+###############################################################################
+###############################################################################
+
+define('BB2_CWD', dirname(__FILE__));
+
+// Settings you can adjust for Bad Behavior.
+// Change these by changing the corresponding TightURL settings in
+// tighturl.config.inc.php instead of editing this file.
+
+$bb2_settings_defaults = array( 'log_table' => $dbtable . '_bb2',
+ 'display_stats' => $BBstats,
+ 'strict' => $BBstrict,
+ 'verbose' => $BBverbose,
+ 'logging' => $BBLogging
+);
+
+// Bad Behavior callback functions.
+
+// Return current time in the format preferred by your database.
+function bb2_db_date() {
+ return gmdate('Y-m-d H:i:s'); // Example is MySQL format
+}
+
+// Return affected rows from most recent query.
+function bb2_db_affected_rows() {
+ return mysql_affected_rows();
+}
+
+// Escape a string for database usage
+function bb2_db_escape($string) {
+ return mysql_real_escape_string($string);
+}
+
+// Return the number of rows in a particular query.
+function bb2_db_num_rows($result) {
+ if ($result !== FALSE) return mysql_num_rows($result);
+ return 0;
+}
+
+// Run a query and return the results, if any.
+// Should return FALSE if an error occurred.
+// Bad Behavior will use the return value here in other callbacks.
+function bb2_db_query($query) {
+ return mysql_query($query);
+}
+
+// Return all rows of a particular query in an array.
+
+function bb2_db_rows($result) {
+ $rows = array();
+ while ($row = mysql_fetch_assoc($result)) {
+ $rows[] = $row;
+ }
+ return $rows;
+}
+
+// Return emergency contact email address.
+function bb2_email() {
+ return $SiteAdminEmail;
+}
+
+// read settings from TightURL
+function bb2_read_settings() {
+ global $bb2_settings_defaults;
+ $settings = $bb2_settings_defaults;
+ return $settings;
+}
+
+// write settings to TightURL
+function bb2_write_settings($settings) {
+ return false;
+}
+
+// installation
+function bb2_install() {
+ return bb2_db_query("CREATE TABLE IF NOT EXISTS `".$settings['log_table']."` (
+ `id` INT(11) NOT NULL auto_increment,
+ `ip` TEXT NOT NULL,
+ `date` DATETIME NOT NULL default '0000-00-00 00:00:00',
+ `request_method` TEXT NOT NULL,
+ `request_uri` TEXT NOT NULL,
+ `server_protocol` TEXT NOT NULL,
+ `http_headers` TEXT NOT NULL,
+ `user_agent` TEXT NOT NULL,
+ `request_entity` TEXT NOT NULL,
+ `key` TEXT NOT NULL,
+ INDEX (`ip`(15)),
+ INDEX (`user_agent`(10)),
+ PRIMARY KEY (`id`))");
+}
+
+// Screener
+// Insert this into the section of your HTML through a template call
+// or whatever is appropriate. This is optional we'll fall back to cookies
+// if you don't use it.
+function bb2_insert_head() {
+ global $bb2_javascript;
+ return $bb2_javascript;
+}
+
+// Display stats
+function bb2_insert_stats($force = false) {
+ $settings = bb2_read_settings();
+
+ if ($force || $settings['display_stats']) {
+ $blocked = bb2_db_query("SELECT COUNT(*) FROM " . $settings['log_table'] . " WHERE `key` NOT LIKE '00000000'");
+ if ($blocked !== FALSE) {
+ if (! isset($blocked[0]["COUNT(*)"])) {
+ $count = 0;
+ }
+ else {
+ $count = $blocked[0]["COUNT(*)"];
+ }
+ $ret = '
Bad Behavior has blocked ' . $count . ' access attempt(s) in the last 7 days.';
+ }
+ else {
+ $ret = "";
+ }
+ }
+ return($ret);
+}
+
+// Return the top-level relative path of wherever we are (for cookies)
+// You should provide in $url the top-level URL for your site.
+function bb2_relative_path() {
+ global $self;
+ return $self;
+}
+
+// Calls inward to Bad Behavior itself.
+require_once(BB2_CWD . "/bad-behavior/version.inc.php");
+require_once(BB2_CWD . "/bad-behavior/core.inc.php");
+
+bb2_start(bb2_read_settings());
+
+?>
diff --git a/bad-behavior/bad-behavior-wordpress-admin.php b/bad-behavior/bad-behavior-wordpress-admin.php
new file mode 100644
index 0000000..2ab543c
--- /dev/null
+++ b/bad-behavior/bad-behavior-wordpress-admin.php
@@ -0,0 +1,287 @@
+= 4772) { // Version 2.1 or later
+ add_management_page(__("Bad Behavior"), __("Bad Behavior"), 8, 'bb2_manage', 'bb2_manage');
+ }
+ @session_start();
+ }
+}
+
+function bb2_clean_log_link($uri) {
+ foreach (array("paged", "ip", "key", "blocked", "request_method", "user_agent") as $arg) {
+ $uri = remove_query_arg($arg, $uri);
+ }
+ return $uri;
+}
+
+function bb2_httpbl_lookup($ip) {
+ $engines = array(
+ 2 => "Bloglines",
+ 5 => "Googlebot",
+ 8 => "msnbot",
+ 9 => "Yahoo! Slurp",
+ );
+ $settings = bb2_read_settings();
+ $httpbl_key = $settings['httpbl_key'];
+ if (!$httpbl_key) return false;
+
+ $r = $_SESSION['httpbl'][$ip];
+ $d = "";
+ if (!$r) { // Lookup
+ $find = implode('.', array_reverse(explode('.', $ip)));
+ $result = gethostbynamel("${httpbl_key}.${find}.dnsbl.httpbl.org.");
+ if (!empty($result)) {
+ $r = $result[0];
+ $_SESSION['httpbl'][$ip] = $r;
+ }
+ }
+ if ($r) { // Interpret
+ $ip = explode('.', $r);
+ if ($ip[0] == 127) {
+ if ($ip[3] == 0) {
+ if ($engines[$ip[2]]) {
+ $d .= $engines[$ip[2]];
+ } else {
+ $d .= "Search engine ${ip[2]}
\n";
+ }
+ }
+ if ($ip[3] & 1) {
+ $d .= "Suspicious
\n";
+ }
+ if ($ip[3] & 2) {
+ $d .= "Harvester
\n";
+ }
+ if ($ip[3] & 4) {
+ $d .= "Comment Spammer
\n";
+ }
+ if ($ip[3] & 7) {
+ $d .= "Threat level ${ip[2]}
\n";
+ }
+ if ($ip[3] > 0) {
+ $d .= "Age ${ip[1]} days
\n";
+ }
+ }
+ }
+ return $d;
+}
+
+function bb2_manage() {
+ global $wpdb;
+
+ $request_uri = $_SERVER["REQUEST_URI"];
+ $settings = bb2_read_settings();
+ $rows_per_page = 100;
+ $where = "";
+
+ // Get query variables desired by the user with input validation
+ $paged = 0 + $_GET['paged']; if (!$paged) $paged = 1;
+ if ($_GET['key']) $where .= "AND `key` = '" . $wpdb->escape($_GET['key']) . "' ";
+ if ($_GET['blocked']) $where .= "AND `key` != '00000000' ";
+ if ($_GET['ip']) $where .= "AND `ip` = '" . $wpdb->escape($_GET['ip']) . "' ";
+ if ($_GET['user_agent']) $where .= "AND `user_agent` = '" . $wpdb->escape($_GET['user_agent']) . "' ";
+ if ($_GET['request_method']) $where .= "AND `request_method` = '" . $wpdb->escape($_GET['request_method']) . "' ";
+
+ // Query the DB based on variables selected
+ $r = bb2_db_query("SELECT COUNT(*) FROM `" . $settings['log_table']);
+ $results = bb2_db_rows($r);
+ $totalcount = $results[0]["COUNT(*)"];
+ $r = bb2_db_query("SELECT COUNT(*) FROM `" . $settings['log_table'] . "` WHERE 1=1 " . $where);
+ $results = bb2_db_rows($r);
+ $count = $results[0]["COUNT(*)"];
+ $pages = ceil($count / 100);
+ $r = bb2_db_query("SELECT * FROM `" . $settings['log_table'] . "` WHERE 1=1 " . $where . "ORDER BY `date` DESC LIMIT " . ($paged - 1) * $rows_per_page . "," . $rows_per_page);
+ $results = bb2_db_rows($r);
+
+ // Display rows to the user
+?>
+
+
+
+
+
+
diff --git a/bad-behavior/bad-behavior-wordpress.php b/bad-behavior/bad-behavior-wordpress.php
new file mode 100644
index 0000000..98532a6
--- /dev/null
+++ b/bad-behavior/bad-behavior-wordpress.php
@@ -0,0 +1,173 @@
+rows_affected;
+}
+
+// Escape a string for database usage
+function bb2_db_escape($string) {
+ global $wpdb;
+
+ return $wpdb->escape($string);
+}
+
+// Return the number of rows in a particular query.
+function bb2_db_num_rows($result) {
+ if ($result !== FALSE)
+ return count($result);
+ return 0;
+}
+
+// Run a query and return the results, if any.
+// Should return FALSE if an error occurred.
+// Bad Behavior will use the return value here in other callbacks.
+function bb2_db_query($query) {
+ global $wpdb;
+
+ $wpdb->hide_errors();
+ $result = $wpdb->get_results($query, ARRAY_A);
+ $wpdb->show_errors();
+ if (mysql_error()) {
+ return FALSE;
+ }
+ return $result;
+}
+
+// Return all rows in a particular query.
+// Should contain an array of all rows generated by calling mysql_fetch_assoc()
+// or equivalent and appending the result of each call to an array.
+// For WP this is pretty much a no-op.
+function bb2_db_rows($result) {
+ return $result;
+}
+
+// Return emergency contact email address.
+function bb2_email() {
+ return get_bloginfo('admin_email');
+}
+
+// retrieve settings from database
+function bb2_read_settings() {
+ global $wpdb;
+
+ // Add in default settings when they aren't yet present in WP
+ $settings = get_settings('bad_behavior_settings');
+ if (!$settings) $settings = array();
+ return array_merge(array('log_table' => $wpdb->prefix . 'bad_behavior', 'display_stats' => true, 'strict' => false, 'verbose' => false, 'logging' => true, 'httpbl_key' => '', 'httpbl_threat' => '25', 'httpbl_maxage' => '30',), $settings);
+}
+
+// write settings to database
+function bb2_write_settings($settings) {
+ update_option('bad_behavior_settings', $settings);
+}
+
+// installation
+function bb2_install() {
+ $settings = bb2_read_settings();
+ if (!$settings['logging']) return;
+ bb2_db_query(bb2_table_structure($settings['log_table']));
+}
+
+// Cute timer display; screener
+function bb2_insert_head() {
+ global $bb2_timer_total;
+ global $bb2_javascript;
+ echo "\n\n";
+ echo $bb2_javascript;
+}
+
+// Display stats?
+function bb2_insert_stats($force = false) {
+ $settings = bb2_read_settings();
+
+ if ($force || $settings['display_stats']) {
+ $blocked = bb2_db_query("SELECT COUNT(*) FROM " . $settings['log_table'] . " WHERE `key` NOT LIKE '00000000'");
+ if ($blocked !== FALSE) {
+ echo sprintf('%1$s %2$s %3$s %4$s
', __('Bad Behavior'), __('has blocked'), $blocked[0]["COUNT(*)"], __('access attempts in the last 7 days.'));
+ }
+ }
+}
+
+// Return the top-level relative path of wherever we are (for cookies)
+function bb2_relative_path() {
+ $url = parse_url(get_bloginfo('url'));
+ return $url['path'] . '/';
+}
+
+// FIXME: some sort of hack to run install on 1.5 (and older?) blogs
+// FIXME: figure out what's wrong on 2.0 that this doesn't work
+// register_activation_hook(__FILE__, 'bb2_install');
+//add_action('activate_bb2/bad-behavior-wordpress.php', 'bb2_install');
+add_action('wp_head', 'bb2_insert_head');
+add_action('wp_footer', 'bb2_insert_stats');
+
+// Calls inward to Bad Behavor itself.
+require_once(BB2_CWD . "/bad-behavior/version.inc.php");
+require_once(BB2_CWD . "/bad-behavior/core.inc.php");
+bb2_install(); // FIXME: see above
+
+if (is_admin() || strstr($_SERVER['PHP_SELF'], 'wp-admin/')) { // 1.5 kludge
+ #wp_enqueue_script("admin-forms");
+ require_once(BB2_CWD . "/bad-behavior-wordpress-admin.php");
+}
+
+bb2_start(bb2_read_settings());
+
+$bb2_mtime = explode(" ", microtime());
+$bb2_timer_stop = $bb2_mtime[1] + $bb2_mtime[0];
+$bb2_timer_total = $bb2_timer_stop - $bb2_timer_start;
+
+?>
diff --git a/bad-behavior/bad-behavior/banned.inc.php b/bad-behavior/bad-behavior/banned.inc.php
new file mode 100644
index 0000000..3caa497
--- /dev/null
+++ b/bad-behavior/bad-behavior/banned.inc.php
@@ -0,0 +1,49 @@
+
+
+
+
+HTTP Error
+
+
+Error
+We're sorry, but we could not fulfill your request for
+ on this server.
+
+Your technical support key is:
+You can use this key to fix this problem yourself.
+If you are unable to fix the problem yourself, please contact "> and be sure to provide the technical support key shown above.
+
diff --git a/bad-behavior/bad-behavior/blackhole.inc.php b/bad-behavior/bad-behavior/blackhole.inc.php
new file mode 100644
index 0000000..08564fb
--- /dev/null
+++ b/bad-behavior/bad-behavior/blackhole.inc.php
@@ -0,0 +1,51 @@
+ array("127.0.0.4"), // CBL is problematic
+ "dnsbl.sorbs.net" => array("127.0.0.10",), // Dynamic IPs only
+ "list.dsbl.org" => array(),
+ "dnsbl.ioerror.us" => array(),
+ );
+
+ // Check the blackhole lists
+ $ip = $package['ip'];
+ $find = implode('.', array_reverse(explode('.', $ip)));
+ foreach ($bb2_blackhole_lists as $dnsbl) {
+ $result = gethostbynamel($find . "." . $dnsbl . ".");
+ if (!empty($result)) {
+ // Got a match and it isn't on the exception list
+ $result = @array_diff($result, $bb2_blackhole_exceptions[$dnsbl]);
+ if (!empty($result)) {
+ return '136673cd';
+ }
+ }
+ }
+ return false;
+}
+
+function bb2_httpbl($settings, $package) {
+ if (!@$settings['httpbl_key']) return false;
+
+ $find = implode('.', array_reverse(explode('.', $package['ip'])));
+ $result = gethostbynamel($settings['httpbl_key'].".${find}.dnsbl.httpbl.org.");
+ if (!empty($result)) {
+ $ip = explode('.', $result[0]);
+ if ($ip[0] == 127 && ($ip[3] & 7) && $ip[2] >= $settings['httpbl_threat'] && $ip[1] >= $settings['httpbl_maxage']) {
+ return '2b021b1f';
+ }
+ }
+ return false;
+}
+?>
diff --git a/bad-behavior/bad-behavior/blackhole.inc.php~ b/bad-behavior/bad-behavior/blackhole.inc.php~
new file mode 100644
index 0000000..cbc0826
--- /dev/null
+++ b/bad-behavior/bad-behavior/blackhole.inc.php~
@@ -0,0 +1,51 @@
+ array("127.0.0.4"), // CBL is problematic
+ "dnsbl.sorbs.net" => array("127.0.0.10",), // Dynamic IPs only
+ "list.dsbl.org" => array(),
+ "dnsbl.ioerror.us" => array(),
+ );
+
+ // Check the blackhole lists
+ $ip = $package['ip'];
+ $find = implode('.', array_reverse(explode('.', $ip)));
+ foreach ($bb2_blackhole_lists as $dnsbl) {
+ $result = gethostbynamel($find . "." . $dnsbl . ".");
+ if (!empty($result)) {
+ // Got a match and it isn't on the exception list
+ $result = @array_diff($result, $bb2_blackhole_exceptions[$dnsbl]);
+ if (!empty($result)) {
+ return '136673cd';
+ }
+ }
+ }
+ return false;
+}
+
+function bb2_httpbl($settings, $package) {
+ if (!$settings['httpbl_key']) return false;
+
+ $find = implode('.', array_reverse(explode('.', $package['ip'])));
+ $result = gethostbynamel($settings['httpbl_key'].".${find}.dnsbl.httpbl.org.");
+ if (!empty($result)) {
+ $ip = explode('.', $result[0]);
+ if ($ip[0] == 127 && ($ip[3] & 7) && $ip[2] >= $settings['httpbl_threat'] && $ip[1] >= $settings['httpbl_maxage']) {
+ return '2b021b1f';
+ }
+ }
+ return false;
+}
+?>
diff --git a/bad-behavior/bad-behavior/blacklist.inc.php b/bad-behavior/bad-behavior/blacklist.inc.php
new file mode 100644
index 0000000..e77719f
--- /dev/null
+++ b/bad-behavior/bad-behavior/blacklist.inc.php
@@ -0,0 +1,121 @@
+
diff --git a/bad-behavior/bad-behavior/common_tests.inc.php b/bad-behavior/bad-behavior/common_tests.inc.php
new file mode 100644
index 0000000..4ffc1ab
--- /dev/null
+++ b/bad-behavior/bad-behavior/common_tests.inc.php
@@ -0,0 +1,137 @@
+
diff --git a/bad-behavior/bad-behavior/core.inc.php b/bad-behavior/bad-behavior/core.inc.php
new file mode 100644
index 0000000..641106b
--- /dev/null
+++ b/bad-behavior/bad-behavior/core.inc.php
@@ -0,0 +1,208 @@
+ $v) {
+ $headers .= bb2_db_escape("$h: $v\n");
+ }
+ $request_entity = "";
+ if (!strcasecmp($request_method, "POST")) {
+ foreach ($package['request_entity'] as $h => $v) {
+ $request_entity .= bb2_db_escape("$h: $v\n");
+ }
+ }
+ return "INSERT INTO `" . bb2_db_escape($settings['log_table']) . "`
+ (`ip`, `date`, `request_method`, `request_uri`, `server_protocol`, `http_headers`, `user_agent`, `request_entity`, `key`) VALUES
+ ('$ip', '$date', '$request_method', '$request_uri', '$server_protocol', '$headers', '$user_agent', '$request_entity', '$key')";
+}
+
+// Kill 'em all!
+function bb2_banned($settings, $package, $key, $previous_key=false)
+{
+ // Some spambots hit too hard. Slow them down a bit.
+ sleep(2);
+
+ require_once(BB2_CORE . "/banned.inc.php");
+ bb2_display_denial($settings, $key, $previous_key);
+ bb2_log_denial($settings, $package, $key, $previous_key);
+ if (is_callable('bb2_banned_callback')) {
+ bb2_banned_callback($settings, $package, $key);
+ }
+ // Penalize the spammers some more
+ require_once(BB2_CORE . "/housekeeping.inc.php");
+ bb2_housekeeping($settings, $package);
+ die();
+}
+
+function bb2_approved($settings, $package)
+{
+ // Dirk wanted this
+ if (is_callable('bb2_approved_callback')) {
+ bb2_approved_callback($settings, $package);
+ }
+
+ // Decide what to log on approved requests.
+ if (($settings['verbose'] && $settings['logging']) || empty($package['user_agent'])) {
+ bb2_db_query(bb2_insert($settings, $package, "00000000"));
+ }
+}
+
+// Check the results of a particular test; see below for usage
+// Returns FALSE if test passed (yes this is backwards)
+function bb2_test($settings, $package, $result)
+{
+ if ($result !== FALSE)
+ {
+ bb2_banned($settings, $package, $result);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+// Let God sort 'em out!
+function bb2_start($settings)
+{
+ // Gather up all the information we need, first of all.
+ $headers = bb2_load_headers();
+ // Postprocess the headers to mixed-case
+ // FIXME: get the world to stop using PHP as CGI
+ $headers_mixed = array();
+ foreach ($headers as $h => $v) {
+ $headers_mixed[uc_all($h)] = $v;
+ }
+
+ // We use these frequently. Keep a copy close at hand.
+ $ip = $_SERVER['REMOTE_ADDR'];
+ $request_method = $_SERVER['REQUEST_METHOD'];
+ $request_uri = $_SERVER['REQUEST_URI'];
+ $server_protocol = $_SERVER['SERVER_PROTOCOL'];
+ @$user_agent = $_SERVER['HTTP_USER_AGENT'];
+
+ // Reconstruct the HTTP entity, if present.
+ $request_entity = array();
+ if (!strcasecmp($request_method, "POST") || !strcasecmp($request_method, "PUT")) {
+ foreach ($_POST as $h => $v) {
+ $request_entity[$h] = $v;
+ }
+ }
+
+ $package = array('ip' => $ip, 'headers' => $headers, 'headers_mixed' => $headers_mixed, 'request_method' => $request_method, 'request_uri' => $request_uri, 'server_protocol' => $server_protocol, 'request_entity' => $request_entity, 'user_agent' => $user_agent, 'is_browser' => false);
+
+ // Please proceed to the security checkpoint and have your
+ // identification and boarding pass ready.
+
+ // First check the whitelist
+ require_once(BB2_CORE . "/whitelist.inc.php");
+ if (!bb2_whitelist($package)) {
+ // Now check the blacklist
+ require_once(BB2_CORE . "/blacklist.inc.php");
+ bb2_test($settings, $package, bb2_blacklist($package));
+
+ // Check the http:BL
+ require_once(BB2_CORE . "/blackhole.inc.php");
+ bb2_test($settings, $package, bb2_httpbl($settings, $package));
+
+ // Check for common stuff
+ require_once(BB2_CORE . "/common_tests.inc.php");
+ bb2_test($settings, $package, bb2_protocol($settings, $package));
+ bb2_test($settings, $package, bb2_cookies($settings, $package));
+ bb2_test($settings, $package, bb2_misc_headers($settings, $package));
+
+ // Specific checks
+ @$ua = $headers_mixed['User-Agent'];
+ // MSIE checks
+ if (stripos($ua, "MSIE") !== FALSE) {
+ $package['is_browser'] = true;
+ if (stripos($ua, "Opera") !== FALSE) {
+ require_once(BB2_CORE . "/opera.inc.php");
+ bb2_test($settings, $package, bb2_opera($package));
+ } else {
+ require_once(BB2_CORE . "/msie.inc.php");
+ bb2_test($settings, $package, bb2_msie($package));
+ }
+ } elseif (stripos($ua, "Konqueror") !== FALSE) {
+ $package['is_browser'] = true;
+ require_once(BB2_CORE . "/konqueror.inc.php");
+ bb2_test($settings, $package, bb2_konqueror($package));
+ } elseif (stripos($ua, "Opera") !== FALSE) {
+ $package['is_browser'] = true;
+ require_once(BB2_CORE . "/opera.inc.php");
+ bb2_test($settings, $package, bb2_opera($package));
+ } elseif (stripos($ua, "Safari") !== FALSE) {
+ $package['is_browser'] = true;
+ require_once(BB2_CORE . "/safari.inc.php");
+ bb2_test($settings, $package, bb2_safari($package));
+ } elseif (stripos($ua, "Lynx") !== FALSE) {
+ $package['is_browser'] = true;
+ require_once(BB2_CORE . "/lynx.inc.php");
+ bb2_test($settings, $package, bb2_lynx($package));
+ } elseif (stripos($ua, "MovableType") !== FALSE) {
+ require_once(BB2_CORE . "/movabletype.inc.php");
+ bb2_test($settings, $package, bb2_movabletype($package));
+ } elseif (stripos($ua, "msnbot") !== FALSE || stripos($ua, "MS Search") !== FALSE) {
+ require_once(BB2_CORE . "/msnbot.inc.php");
+ bb2_test($settings, $package, bb2_msnbot($package));
+ } elseif (stripos($ua, "Googlebot") !== FALSE || stripos($ua, "Mediapartners-Google") !== FALSE) {
+ require_once(BB2_CORE . "/google.inc.php");
+ bb2_test($settings, $package, bb2_google($package));
+ } elseif (stripos($ua, "Mozilla") !== FALSE && stripos($ua, "Mozilla") == 0) {
+ $package['is_browser'] = true;
+ require_once(BB2_CORE . "/mozilla.inc.php");
+ bb2_test($settings, $package, bb2_mozilla($package));
+ }
+
+ // More intensive screening applies to POST requests
+ if (!strcasecmp('POST', $package['request_method'])) {
+ require_once(BB2_CORE . "/post.inc.php");
+ bb2_test($settings, $package, bb2_post($settings, $package));
+ }
+ }
+
+ // Last chance screening.
+ require_once(BB2_CORE . "/screener.inc.php");
+ bb2_screener($settings, $package);
+
+ // And that's about it.
+ bb2_approved($settings, $package);
+ return true;
+}
+?>
diff --git a/bad-behavior/bad-behavior/functions.inc.php b/bad-behavior/bad-behavior/functions.inc.php
new file mode 100644
index 0000000..22e8882
--- /dev/null
+++ b/bad-behavior/bad-behavior/functions.inc.php
@@ -0,0 +1,70 @@
+$word) {
+ $temp[$key] = ucfirst(strtolower($word));
+ }
+ return join ('', $temp);
+}
+
+// Determine if an IP address resides in a CIDR netblock or netblocks.
+function match_cidr($addr, $cidr) {
+ $output = false;
+
+ if (is_array($cidr)) {
+ foreach ($cidr as $cidrlet) {
+ if (match_cidr($addr, $cidrlet)) {
+ $output = true;
+ }
+ }
+ } else {
+ @list($ip, $mask) = explode('/', $cidr);
+ if (!$mask) $mask = 32;
+ $mask = pow(2,32) - pow(2, (32 - $mask));
+ $output = ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
+ }
+ return $output;
+}
+
+// Obtain all the HTTP headers.
+// NB: on PHP-CGI we have to fake it out a bit, since we can't get the REAL
+// headers. Run PHP as Apache 2.0 module if possible for best results.
+function bb2_load_headers() {
+ if (!is_callable('getallheaders')) {
+ $headers = array();
+ foreach ($_SERVER as $h => $v)
+ if (ereg('HTTP_(.+)', $h, $hp))
+ $headers[str_replace("_", "-", uc_all($hp[1]))] = $v;
+ } else {
+ $headers = getallheaders();
+ }
+ return $headers;
+}
+
+?>
diff --git a/bad-behavior/bad-behavior/google.inc.php b/bad-behavior/bad-behavior/google.inc.php
new file mode 100644
index 0000000..956bdb4
--- /dev/null
+++ b/bad-behavior/bad-behavior/google.inc.php
@@ -0,0 +1,13 @@
+
diff --git a/bad-behavior/bad-behavior/housekeeping.inc.php b/bad-behavior/bad-behavior/housekeeping.inc.php
new file mode 100644
index 0000000..b837ee0
--- /dev/null
+++ b/bad-behavior/bad-behavior/housekeeping.inc.php
@@ -0,0 +1,16 @@
+
diff --git a/bad-behavior/bad-behavior/index.html b/bad-behavior/bad-behavior/index.html
new file mode 100644
index 0000000..e69de29
diff --git a/bad-behavior/bad-behavior/konqueror.inc.php b/bad-behavior/bad-behavior/konqueror.inc.php
new file mode 100644
index 0000000..3a84dba
--- /dev/null
+++ b/bad-behavior/bad-behavior/konqueror.inc.php
@@ -0,0 +1,17 @@
+
diff --git a/bad-behavior/bad-behavior/lynx.inc.php b/bad-behavior/bad-behavior/lynx.inc.php
new file mode 100644
index 0000000..a59ba10
--- /dev/null
+++ b/bad-behavior/bad-behavior/lynx.inc.php
@@ -0,0 +1,13 @@
+
diff --git a/bad-behavior/bad-behavior/movabletype.inc.php b/bad-behavior/bad-behavior/movabletype.inc.php
new file mode 100644
index 0000000..b15fe9c
--- /dev/null
+++ b/bad-behavior/bad-behavior/movabletype.inc.php
@@ -0,0 +1,14 @@
+
diff --git a/bad-behavior/bad-behavior/mozilla.inc.php b/bad-behavior/bad-behavior/mozilla.inc.php
new file mode 100644
index 0000000..a1cac82
--- /dev/null
+++ b/bad-behavior/bad-behavior/mozilla.inc.php
@@ -0,0 +1,19 @@
+
diff --git a/bad-behavior/bad-behavior/msie.inc.php b/bad-behavior/bad-behavior/msie.inc.php
new file mode 100644
index 0000000..8709d6b
--- /dev/null
+++ b/bad-behavior/bad-behavior/msie.inc.php
@@ -0,0 +1,25 @@
+
diff --git a/bad-behavior/bad-behavior/msnbot.inc.php b/bad-behavior/bad-behavior/msnbot.inc.php
new file mode 100644
index 0000000..0341da1
--- /dev/null
+++ b/bad-behavior/bad-behavior/msnbot.inc.php
@@ -0,0 +1,13 @@
+
diff --git a/bad-behavior/bad-behavior/opera.inc.php b/bad-behavior/bad-behavior/opera.inc.php
new file mode 100644
index 0000000..e29a8c7
--- /dev/null
+++ b/bad-behavior/bad-behavior/opera.inc.php
@@ -0,0 +1,13 @@
+
diff --git a/bad-behavior/bad-behavior/post.inc.php b/bad-behavior/bad-behavior/post.inc.php
new file mode 100644
index 0000000..ecbfc7e
--- /dev/null
+++ b/bad-behavior/bad-behavior/post.inc.php
@@ -0,0 +1,80 @@
+ $value) {
+ $pos = strpos($key, " document.write");
+ if ($pos !== FALSE) {
+ return "dfd9b1ad";
+ }
+ }
+
+ // If Referer exists, it should refer to a page on our site
+ if (array_key_exists('Referer', $package['headers_mixed']) && stripos($package['headers_mixed']['Referer'], $package['headers_mixed']['Host']) === FALSE) {
+ return "cd361abb";
+ }
+
+ // Screen by cookie/JavaScript form add
+ if (isset($_COOKIE[BB2_COOKIE])) {
+ $screener1 = explode(" ", $_COOKIE[BB2_COOKIE]);
+ } else {
+ $screener1 = array(0);
+ }
+ if (isset($_POST[BB2_COOKIE])) {
+ $screener2 = explode(" ", $_POST[BB2_COOKIE]);
+ } else {
+ $screener2 = array(0);
+ }
+ $screener = max($screener1[0], $screener2[0]);
+
+ if ($screener > 0) {
+ // Posting too fast? 5 sec
+ // FIXME: even 5 sec is too intrusive
+ // if ($screener + 5 > time())
+ // return "408d7e72";
+ // Posting too slow? 48 hr
+ if ($screener + 172800 < time())
+ return "b40c8ddc";
+
+ // Screen by IP address
+ $ip = ip2long($package['ip']);
+ $ip_screener = ip2long($screener[1]);
+// FIXME: This is b0rked, but why?
+// if ($ip && $ip_screener && abs($ip_screener - $ip) > 256)
+// return "c1fa729b";
+
+ if (!empty($package['headers_mixed']['X-Forwarded-For'])) {
+ $ip = $package['headers_mixed']['X-Forwarded-For'];
+ }
+ // Screen for user agent changes
+ // User connected previously with blank user agent
+// $q = bb2_db_query("SELECT `ip` FROM " . $settings['log_table'] . " WHERE (`ip` = '" . $package['ip'] . "' OR `ip` = '" . $screener[1] . "') AND `user_agent` != '" . $package['user_agent'] . "' AND `date` > DATE_SUB('" . bb2_db_date() . "', INTERVAL 5 MINUTE)");
+ // Damnit, too many ways for this to fail :(
+// if ($q !== FALSE && $q != NULL && bb2_db_num_rows($q) > 0)
+// return "799165c2";
+ }
+
+ return false;
+}
+
+?>
diff --git a/bad-behavior/bad-behavior/responses.inc.php b/bad-behavior/bad-behavior/responses.inc.php
new file mode 100644
index 0000000..56fdf95
--- /dev/null
+++ b/bad-behavior/bad-behavior/responses.inc.php
@@ -0,0 +1,48 @@
+ array('response' => 200, 'explanation' => '', 'log' => 'Permitted'),
+ '136673cd' => array('response' => 403, 'explanation' => 'Your Internet Protocol address is listed on a blacklist of addresses involved in malicious or illegal activity. See the listing below for more details on specific blacklists and removal procedures.', 'log' => 'IP address found on external blacklist'),
+ '17566707' => array('response' => 403, 'explanation' => 'An invalid request was received from your browser. This may be caused by a malfunctioning proxy server or browser privacy software.', 'log' => 'Required header \'Accept\' missing'),
+ '17f4e8c8' => array('response' => 403, 'explanation' => 'You do not have permission to access this server.', 'log' => 'User-Agent was found on blacklist'),
+ '21f11d3f' => array('response' => 403, 'explanation' => 'An invalid request was received. You claimed to be a mobile Web device, but you do not actually appear to be a mobile Web device.', 'log' => 'User-Agent claimed to be AvantGo, claim appears false'),
+ '2b021b1f' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. Before trying again, run anti-virus and anti-spyware software and remove any viruses and spyware from your computer.', 'log' => 'IP address found on http:BL blacklist'),
+ '2b90f772' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. If you are using the Opera browser, then Opera must appear in your user agent.', 'log' => 'Connection: TE present, not supported by MSIE'),
+ '35ea7ffa' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. Check your browser\'s language and locale settings.', 'log' => 'Invalid language specified'),
+ '408d7e72' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. Before trying again, run anti-virus and anti-spyware software and remove any viruses and spyware from your computer.', 'log' => 'POST comes too quickly after GET'),
+ '41feed15' => array('response' => 400, 'explanation' => 'An invalid request was received. This may be caused by a malfunctioning proxy server. Bypass the proxy server and connect directly, or contact your proxy server administrator.', 'log' => 'Header \'Pragma\' without \'Cache-Control\' prohibited for HTTP/1.1 requests'),
+ '45b35e30' => array('response' => 403, 'explanation' => 'An invalid request was received from your browser. This may be caused by a malfunctioning proxy server or browser privacy software.', 'log' => 'Header \'Referer\' is corrupt'),
+ '57796684' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. Before trying again, run anti-virus and anti-spyware software and remove any viruses and spyware from your computer.', 'log' => 'Prohibited header \'X-Aaaaaaaaaa\' or \'X-Aaaaaaaaaaaa\' present'),
+ '582ec5e4' => array('response' => 400, 'explanation' => 'An invalid request was received. If you are using a proxy server, bypass the proxy server or contact your proxy server administrator. This may also be caused by a bug in the Opera web browser.', 'log' => '"Header \'TE\' present but TE not specified in \'Connection\' header'),
+ '69920ee5' => array('response' => 403, 'explanation' => 'An invalid request was received from your browser. This may be caused by a malfunctioning proxy server or browser privacy software.', 'log' => 'Header \'Referer\' present but blank'),
+ '6c502ff1' => array('response' => 403, 'explanation' => 'You do not have permission to access this server.', 'log' => 'Bot not fully compliant with RFC 2965'),
+ '799165c2' => array('response' => 403, 'explanation' => 'You do not have permission to access this server.', 'log' => 'Rotating user-agents detected'),
+ '7a06532b' => array('response' => 400, 'explanation' => 'An invalid request was received from your browser. This may be caused by a malfunctioning proxy server or browser privacy software.', 'log' => 'Required header \'Accept-Encoding\' missing'),
+ '7ad04a8a' => array('response' => 400, 'explanation' => 'The automated program you are using is not permitted to access this server. Please use a different program or a standard Web browser.', 'log' => 'Prohibited header \'Range\' present'),
+ '7d12528e' => array('response' => 403, 'explanation' => 'You do not have permission to access this server.', 'log' => 'Prohibited header \'Range\' or \'Content-Range\' in POST request'),
+ '939a6fbb' => array('response' => 403, 'explanation' => 'The proxy server you are using is not permitted to access this server. Please bypass the proxy server, or contact your proxy server administrator.', 'log' => 'Banned proxy server in use'),
+ '9c9e4979' => array('response' => 403, 'explanation' => 'The proxy server you are using is not permitted to access this server. Please bypass the proxy server, or contact your proxy server administrator.', 'log' => 'Prohibited header \'via\' present'),
+ 'a0105122' => array('response' => 417, 'explanation' => 'Expectation failed. Please retry your request.', 'log' => 'Header \'Expect\' prohibited; resend without Expect'),
+ 'a1084bad' => array('response' => 403, 'explanation' => 'You do not have permission to access this server.', 'log' => 'User-Agent claimed to be MSIE, with invalid Windows version'),
+ 'a52f0448' => array('response' => 400, 'explanation' => 'An invalid request was received. This may be caused by a malfunctioning proxy server or browser privacy software. If you are using a proxy server, bypass the proxy server or contact your proxy server administrator.', 'log' => 'Header \'Connection\' contains invalid values'),
+ 'b40c8ddc' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. Before trying again, close your browser, run anti-virus and anti-spyware software and remove any viruses and spyware from your computer.', 'log' => 'POST more than two days after GET'),
+ 'b7830251' => array('response' => 400, 'explanation' => 'Your proxy server sent an invalid request. Please contact the proxy server administrator to have this problem fixed.', 'log' => 'Prohibited header \'Proxy-Connection\' present'),
+ 'b9cc1d86' => array('response' => 403, 'explanation' => 'The proxy server you are using is not permitted to access this server. Please bypass the proxy server, or contact your proxy server administrator.', 'log' => 'Prohibited header \'X-Aaaaaaaaaa\' or \'X-Aaaaaaaaaaaa\' present'),
+ 'c1fa729b' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. Before trying again, run anti-virus and anti-spyware software and remove any viruses and spyware from your computer.', 'log' => 'Use of rotating proxy servers detected'),
+ 'cd361abb' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. Data may not be posted from offsite forms.', 'log' => 'Referer did not point to a form on this site'),
+ 'd60b87c7' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. Before trying again, please remove any viruses or spyware from your computer.', 'log' => 'Trackback received via proxy server'),
+ 'dfd9b1ad' => array('response' => 403, 'explanation' => 'You do not have permission to access this server.', 'log' => 'Request contained a malicious JavaScript or SQL injection attack'),
+ 'e4de0453' => array('response' => 403, 'explanation' => 'An invalid request was received. You claimed to be a major search engine, but you do not appear to actually be a major search engine.', 'log' => 'User-Agent claimed to be msnbot, claim appears to be false'),
+ 'e87553e1' => array('response' => 403, 'explanation' => 'You do not have permission to access this server.', 'log' => 'I know you and I don\'t like you, dirty spammer.'),
+ 'f0dcb3fd' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. Before trying again, run anti-virus and anti-spyware software and remove any viruses and spyware from your computer.', 'log' => 'Web browser attempted to send a trackback'),
+ 'f1182195' => array('response' => 403, 'explanation' => 'An invalid request was received. You claimed to be a major search engine, but you do not appear to actually be a major search engine.', 'log' => 'User-Agent claimed to be Googlebot, claim appears to be false.'),
+ 'f9f2b8b9' => array('response' => 403, 'explanation' => 'You do not have permission to access this server. This may be caused by a malfunctioning proxy server or browser privacy software.', 'log' => 'A User-Agent is required but none was provided.'),
+ );
+
+ if (array_key_exists($key, $bb2_responses)) return $bb2_responses[$key];
+ return array('00000000');
+}
+?>
diff --git a/bad-behavior/bad-behavior/safari.inc.php b/bad-behavior/bad-behavior/safari.inc.php
new file mode 100644
index 0000000..523bdd5
--- /dev/null
+++ b/bad-behavior/bad-behavior/safari.inc.php
@@ -0,0 +1,13 @@
+
diff --git a/bad-behavior/bad-behavior/screener.inc.php b/bad-behavior/bad-behavior/screener.inc.php
new file mode 100644
index 0000000..55da198
--- /dev/null
+++ b/bad-behavior/bad-behavior/screener.inc.php
@@ -0,0 +1,63 @@
+
+
+ ";
+}
+
+function bb2_screener($settings, $package)
+{
+ $cookie_name = BB2_COOKIE;
+
+ // Set up a simple cookie
+ $screener = array(time(), $package['ip']);
+ if (isset($package['headers_mixed']['X-Forwarded-For'])) {
+ array_push($screener, $package['headers_mixed']['X-Forwarded-For']);
+ }
+ if (isset($package['headers_mixed']['Client-Ip'])) {
+ array_push($screener, $package['headers_mixed']['Client-Ip']);
+ }
+
+ $cookie_value = implode(" ", $screener);
+
+ bb2_screener_cookie($settings, $package, BB2_COOKIE, $cookie_value);
+ bb2_screener_javascript($settings, $package, BB2_COOKIE, $cookie_value);
+}
+?>
diff --git a/bad-behavior/bad-behavior/trackback.inc.php b/bad-behavior/bad-behavior/trackback.inc.php
new file mode 100644
index 0000000..bd47e51
--- /dev/null
+++ b/bad-behavior/bad-behavior/trackback.inc.php
@@ -0,0 +1,18 @@
+
diff --git a/bad-behavior/bad-behavior/version.inc.php b/bad-behavior/bad-behavior/version.inc.php
new file mode 100644
index 0000000..b10353f
--- /dev/null
+++ b/bad-behavior/bad-behavior/version.inc.php
@@ -0,0 +1,3 @@
+
diff --git a/bad-behavior/bad-behavior/whitelist.inc.php b/bad-behavior/bad-behavior/whitelist.inc.php
new file mode 100644
index 0000000..ebd9200
--- /dev/null
+++ b/bad-behavior/bad-behavior/whitelist.inc.php
@@ -0,0 +1,58 @@
+
diff --git a/bad-behavior/index.html b/bad-behavior/index.html
new file mode 100644
index 0000000..e69de29
diff --git a/gettext.php b/gettext.php
new file mode 100644
index 0000000..de462f5
--- /dev/null
+++ b/gettext.php
@@ -0,0 +1,401 @@
+.
+ Copyright (c) 2005 Nico Kaiser
+
+ This file is part of PHP-gettext.
+
+ PHP-gettext is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ PHP-gettext is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with PHP-gettext; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/**
+ * Provides a simple gettext replacement that works independently from
+ * the system's gettext abilities.
+ * It can read MO files and use them for translating strings.
+ * The files are passed to gettext_reader as a Stream (see streams.php)
+ *
+ * This version has the ability to cache all strings and translations to
+ * speed up the string lookup.
+ * While the cache is enabled by default, it can be switched off with the
+ * second parameter in the constructor (e.g. whenusing very large MO files
+ * that you don't want to keep in memory)
+ */
+class gettext_reader {
+ //public:
+ var $error = 0; // public variable that holds error code (0 if no error)
+
+ //private:
+ var $BYTEORDER = 0; // 0: low endian, 1: big endian
+ var $STREAM = NULL;
+ var $short_circuit = false;
+ var $enable_cache = false;
+ var $originals = NULL; // offset of original table
+ var $translations = NULL; // offset of translation table
+ var $pluralheader = NULL; // cache header field for plural forms
+ var $select_string_function = NULL; // cache function, which chooses plural forms
+ var $total = 0; // total string count
+ var $table_originals = NULL; // table for original strings (offsets)
+ var $table_translations = NULL; // table for translated strings (offsets)
+ var $cache_translations = NULL; // original -> translation mapping
+
+
+ /* Methods */
+
+
+ /**
+ * Reads a 32bit Integer from the Stream
+ *
+ * @access private
+ * @return Integer from the Stream
+ */
+ function readint() {
+ if ($this->BYTEORDER == 0) {
+ // low endian
+ $low_end = unpack('V', $this->STREAM->read(4));
+ return array_shift($low_end);
+ } else {
+ // big endian
+ $big_end = unpack('N', $this->STREAM->read(4));
+ return array_shift($big_end);
+ }
+ }
+
+ /**
+ * Reads an array of Integers from the Stream
+ *
+ * @param int count How many elements should be read
+ * @return Array of Integers
+ */
+ function readintarray($count) {
+ if ($this->BYTEORDER == 0) {
+ // low endian
+ return unpack('V'.$count, $this->STREAM->read(4 * $count));
+ } else {
+ // big endian
+ return unpack('N'.$count, $this->STREAM->read(4 * $count));
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param object Reader the StreamReader object
+ * @param boolean enable_cache Enable or disable caching of strings (default on)
+ */
+ function gettext_reader($Reader, $enable_cache = true) {
+ // If there isn't a StreamReader, turn on short circuit mode.
+ if (! $Reader || isset($Reader->error) ) {
+ $this->short_circuit = true;
+ return;
+ }
+
+ // Caching can be turned off
+ $this->enable_cache = $enable_cache;
+
+ // $MAGIC1 = (int)0x950412de; //bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
+ $MAGIC1 = (int) - 1794895138;
+ // $MAGIC2 = (int)0xde120495; //bug
+ $MAGIC2 = (int) - 569244523;
+ // 64-bit fix
+ $MAGIC3 = (int) 2500072158;
+
+ $this->STREAM = $Reader;
+ $magic = $this->readint();
+ if ($magic == $MAGIC1 || $magic == $MAGIC3) { // to make sure it works for 64-bit platforms
+ $this->BYTEORDER = 0;
+ } elseif ($magic == ($MAGIC2 & 0xFFFFFFFF)) {
+ $this->BYTEORDER = 1;
+ } else {
+ $this->error = 1; // not MO file
+ return false;
+ }
+
+ // FIXME: Do we care about revision? We should.
+ $revision = $this->readint();
+
+ $this->total = $this->readint();
+ $this->originals = $this->readint();
+ $this->translations = $this->readint();
+ }
+
+ /**
+ * Loads the translation tables from the MO file into the cache
+ * If caching is enabled, also loads all strings into a cache
+ * to speed up translation lookups
+ *
+ * @access private
+ */
+ function load_tables() {
+ if (is_array($this->cache_translations) &&
+ is_array($this->table_originals) &&
+ is_array($this->table_translations))
+ return;
+
+ /* get original and translations tables */
+ $this->STREAM->seekto($this->originals);
+ $this->table_originals = $this->readintarray($this->total * 2);
+ $this->STREAM->seekto($this->translations);
+ $this->table_translations = $this->readintarray($this->total * 2);
+
+ if ($this->enable_cache) {
+ $this->cache_translations = array ();
+ /* read all strings in the cache */
+ for ($i = 0; $i < $this->total; $i++) {
+ $this->STREAM->seekto($this->table_originals[$i * 2 + 2]);
+ $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]);
+ $this->STREAM->seekto($this->table_translations[$i * 2 + 2]);
+ $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]);
+ $this->cache_translations[$original] = $translation;
+ }
+ }
+ }
+
+ /**
+ * Returns a string from the "originals" table
+ *
+ * @access private
+ * @param int num Offset number of original string
+ * @return string Requested string if found, otherwise ''
+ */
+ function get_original_string($num) {
+ $length = $this->table_originals[$num * 2 + 1];
+ $offset = $this->table_originals[$num * 2 + 2];
+ if (! $length)
+ return '';
+ $this->STREAM->seekto($offset);
+ $data = $this->STREAM->read($length);
+ return (string)$data;
+ }
+
+ /**
+ * Returns a string from the "translations" table
+ *
+ * @access private
+ * @param int num Offset number of original string
+ * @return string Requested string if found, otherwise ''
+ */
+ function get_translation_string($num) {
+ $length = $this->table_translations[$num * 2 + 1];
+ $offset = $this->table_translations[$num * 2 + 2];
+ if (! $length)
+ return '';
+ $this->STREAM->seekto($offset);
+ $data = $this->STREAM->read($length);
+ return (string)$data;
+ }
+
+ /**
+ * Binary search for string
+ *
+ * @access private
+ * @param string string
+ * @param int start (internally used in recursive function)
+ * @param int end (internally used in recursive function)
+ * @return int string number (offset in originals table)
+ */
+ function find_string($string, $start = -1, $end = -1) {
+ if (($start == -1) or ($end == -1)) {
+ // find_string is called with only one parameter, set start end end
+ $start = 0;
+ $end = $this->total;
+ }
+ if (abs($start - $end) <= 1) {
+ // We're done, now we either found the string, or it doesn't exist
+ $txt = $this->get_original_string($start);
+ if ($string == $txt)
+ return $start;
+ else
+ return -1;
+ } else if ($start > $end) {
+ // start > end -> turn around and start over
+ return $this->find_string($string, $end, $start);
+ } else {
+ // Divide table in two parts
+ $half = (int)(($start + $end) / 2);
+ $cmp = strcmp($string, $this->get_original_string($half));
+ if ($cmp == 0)
+ // string is exactly in the middle => return it
+ return $half;
+ else if ($cmp < 0)
+ // The string is in the upper half
+ return $this->find_string($string, $start, $half);
+ else
+ // The string is in the lower half
+ return $this->find_string($string, $half, $end);
+ }
+ }
+
+ /**
+ * Translates a string
+ *
+ * @access public
+ * @param string string to be translated
+ * @return string translated string (or original, if not found)
+ */
+ function translate($string) {
+ if ($this->short_circuit)
+ return $string;
+ $this->load_tables();
+
+ if ($this->enable_cache) {
+ // Caching enabled, get translated string from cache
+ if (array_key_exists($string, $this->cache_translations))
+ return $this->cache_translations[$string];
+ else
+ return $string;
+ } else {
+ // Caching not enabled, try to find string
+ $num = $this->find_string($string);
+ if ($num == -1)
+ return $string;
+ else
+ return $this->get_translation_string($num);
+ }
+ }
+
+ /**
+ * Get possible plural forms from MO header
+ *
+ * @access private
+ * @return string plural form header
+ */
+ function get_plural_forms() {
+ // lets assume message number 0 is header
+ // this is true, right?
+ $this->load_tables();
+
+ // cache header field for plural forms
+ if (! is_string($this->pluralheader)) {
+ if ($this->enable_cache) {
+ $header = $this->cache_translations[""];
+ } else {
+ $header = $this->get_translation_string(0);
+ }
+ $header .= "\n"; //make sure our regex matches
+ if (eregi("plural-forms: ([^\n]*)\n", $header, $regs))
+ $expr = $regs[1];
+ else
+ $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
+
+ // add parentheses
+ // important since PHP's ternary evaluates from left to right
+ $expr.= ';';
+ $res= '';
+ $p= 0;
+ for ($i= 0; $i < strlen($expr); $i++) {
+ $ch= $expr[$i];
+ switch ($ch) {
+ case '?':
+ $res.= ' ? (';
+ $p++;
+ break;
+ case ':':
+ $res.= ') : (';
+ break;
+ case ';':
+ $res.= str_repeat( ')', $p) . ';';
+ $p= 0;
+ break;
+ default:
+ $res.= $ch;
+ }
+ }
+ $this->pluralheader = $res;
+ }
+
+ return $this->pluralheader;
+ }
+
+ /**
+ * Detects which plural form to take
+ *
+ * @access private
+ * @param n count
+ * @return int array index of the right plural form
+ */
+ function select_string($n) {
+ if (is_null($this->select_string_function)) {
+ $string = $this->get_plural_forms();
+ if (preg_match("/nplurals\s*=\s*(\d+)\s*\;\s*plural\s*=\s*(.*?)\;+/", $string, $matches)) {
+ $nplurals = $matches[1];
+ $expression = $matches[2];
+ $expression = str_replace("n", '$n', $expression);
+ } else {
+ $nplurals = 2;
+ $expression = ' $n == 1 ? 0 : 1 ';
+ }
+ $func_body = "
+ \$plural = ($expression);
+ return (\$plural <= $nplurals)? \$plural : \$plural - 1;";
+ $this->select_string_function = create_function('$n', $func_body);
+ }
+ return call_user_func($this->select_string_function, $n);
+ }
+
+ /**
+ * Plural version of gettext
+ *
+ * @access public
+ * @param string single
+ * @param string plural
+ * @param string number
+ * @return translated plural form
+ */
+ function ngettext($single, $plural, $number) {
+ if ($this->short_circuit) {
+ if ($number != 1)
+ return $plural;
+ else
+ return $single;
+ }
+
+ // find out the appropriate form
+ $select = $this->select_string($number);
+
+ // this should contains all strings separated by NULLs
+ $key = $single.chr(0).$plural;
+
+
+ if ($this->enable_cache) {
+ if (! array_key_exists($key, $this->cache_translations)) {
+ return ($number != 1) ? $plural : $single;
+ } else {
+ $result = $this->cache_translations[$key];
+ $list = explode(chr(0), $result);
+ return $list[$select];
+ }
+ } else {
+ $num = $this->find_string($key);
+ if ($num == -1) {
+ return ($number != 1) ? $plural : $single;
+ } else {
+ $result = $this->get_translation_string($num);
+ $list = explode(chr(0), $result);
+ return $list[$select];
+ }
+ }
+ }
+
+}
+
+?>
diff --git a/local/tighturl.api.tmpl b/local/tighturl.api.tmpl
new file mode 100644
index 0000000..c2adebb
--- /dev/null
+++ b/local/tighturl.api.tmpl
@@ -0,0 +1 @@
+This is the TightURL API documentation. Please stand by.
diff --git a/local/tighturl.config.inc.php b/local/tighturl.config.inc.php
new file mode 100644
index 0000000..9edabd7
--- /dev/null
+++ b/local/tighturl.config.inc.php
@@ -0,0 +1,65 @@
+
+ */
+
+/**
+ * MySQL variables
+ */
+$dbhost = "localhost";
+$dbuser = "dbuser";
+$dbpass = "dbpass";
+$dbname = "tighturl";
+$dbtable = "tighturl";
+
+/**
+ * Site
+ */
+$sitenames = array("example.com","www.example.com");
+
+/**
+ * Operating modes
+ */
+$FOFMethod = FALSE; //FALSE=Use full URL path or mod_rewrite, TRUE=Use 404 Method to compress URLs
+$antiabuse = TRUE; //0=do not run network checks or other anti-abuse measures on submitted URIs, 1=run tests
+ //Must be set to something other than true to deactivate
+$netchecks = TRUE; //0=do not run network checks, 1=run network tests as part of anti-abuse system
+$mustexist = TRUE; //0=do not check URLs to see if they exist, 1=check URLs if netchecks are on.
+$BB2=TRUE; //0=do not use Bad Behavior, 1=Protect your site with Bad Behavior
+
+/**
+ * URIBL variables
+ */
+$uribl = array("multi.surbl.org", "black.uribl.com");
+$uriblurl = array("www.surbl.org", "www.uribl.com");
+
+/** Text strings and style variables
+ *
+ */
+$svcname = "URLSquisher";
+$verbtext = "Squish";
+$pasttext = "Squished";
+$tagline = "Squish long URLs to make short ones";
+$headcolor = "#006600";
+$tablecolor = "#00CC99";
+$copystart = date("Y");
+$copyrightholder = "SquishURL Enterprises";
+$complain = true;
+$validschemes = "(http|https|ftp|sftp)";
+$forbid = "\.(cmd|bat|exe|scr|pif|vbs|js|pif|msi|cdr)";
+
+// Validate IP addresses
+
+$validipv4pattern = ":\/\/(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\."
+ . "(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])"
+ . "\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\/*";
+
+// Reserved URLs
+$ReservedURL = array("x", "rest", "xmlrpc", "soap", "xml", "atom", "rss", "blog",
+ "faq", "help", "about", "api", "code", "source", "docs",
+ "cvs", "arch", "url", "admin", "setup", "svn", "project", "abuse", "exploited");
+?>
diff --git a/local/tighturl.faq.tmpl b/local/tighturl.faq.tmpl
new file mode 100644
index 0000000..bf7dbac
--- /dev/null
+++ b/local/tighturl.faq.tmpl
@@ -0,0 +1 @@
+This is the TightURL FAQ. Please stand by.
diff --git a/local/tighturl.main.tmpl b/local/tighturl.main.tmpl
new file mode 100644
index 0000000..00d41f1
--- /dev/null
+++ b/local/tighturl.main.tmpl
@@ -0,0 +1,12 @@
+ Long URLs that don't fit on one line often aren't clickable after you
+ e-mail them. They can also be tedious to type out on
+ Web-enabled cellphones. $SVCNAME squeezes very long URLs
+ like this:
+
+ http://www.cspan.org/watch/index.asp?Cat=TV&Code=CS&ShowVidDays=30&ShowVidDesc=&ArchiveDays=30
+
+ Down to a $PASTTEXT, compact URL
+ like this:
+
+ http://$HOST$SELF$PARMda42
+
diff --git a/local/tighturl.save.tmpl b/local/tighturl.save.tmpl
new file mode 100644
index 0000000..8c206a8
--- /dev/null
+++ b/local/tighturl.save.tmpl
@@ -0,0 +1,16 @@
+ Your $PASTTEXT URL is: $TIGHTURL (opens in new window)
+
+ That's $TIGHTURLLEN characters, which is $DIFF shorter than the $URLLEN characters of: $URL.
+
+
+
diff --git a/local/tighturl.setup.tmpl b/local/tighturl.setup.tmpl
new file mode 100644
index 0000000..181d3f8
--- /dev/null
+++ b/local/tighturl.setup.tmpl
@@ -0,0 +1,25 @@
+$__HTML :
+$__PARM :
+$__URLLEN :
+$__URL :
+$__INPUT :
+$__TIGHTURLVER :
+$__TIGHTURLLEN :
+$__TIGHTURL :
+$__DIFF :
+$__SVCNAME :
+$__HEADCOLOR :
+$__TABLECOLOR :
+$__TAGLINE :
+$__CPASTTEXT :
+$__PASTTEXT :
+$__VERBTEXT :
+$__CVERBTEXT :
+$__COPYRIGHTHOLDER :
+$__COPYRIGHT :
+$__URIBLS :
+$__HOST :
+$__SELF :
+$__BBSTATS :
+$____VARIABLENAME : Allows you to print $VARIABLENAME literally. :
+
diff --git a/local/tighturl.tmpl b/local/tighturl.tmpl
new file mode 100644
index 0000000..0ece406
--- /dev/null
+++ b/local/tighturl.tmpl
@@ -0,0 +1,38 @@
+
+
+ $SVCNAME
+
+
+ $SVCNAME :: $TAGLINE
+
+ $HTML
+
+
+
+
+ $SVCNAME Bookmarklet: Drag the link
+ $SVCNAME into your browser
+ toolbar. Then you can create a $SVCNAME URL for any page open in your browser window
+ simply by clicking on the bookmarklet.
+
+
+ ©$COPYRIGHT $COPYRIGHTHOLDER.
$SVCNAME uses $URIBLS to
+ protect against redirector abuse by spammers.
+ $SVCNAME is powered by TightURL $TIGHTURLVER,
+ which is Free Software.$BBSTATS
+
+
+
+
diff --git a/streams.php b/streams.php
new file mode 100644
index 0000000..830997d
--- /dev/null
+++ b/streams.php
@@ -0,0 +1,192 @@
+.
+
+ This file is part of PHP-gettext.
+
+ PHP-gettext is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ PHP-gettext is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with PHP-gettext; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+
+// Simple class to wrap file streams, string streams, etc.
+// seek is essential, and it should be byte stream
+class StreamReader {
+ // should return a string [FIXME: perhaps return array of bytes?]
+ function read($bytes) {
+ return false;
+ }
+
+ // should return new position
+ function seekto($position) {
+ return false;
+ }
+
+ // returns current position
+ function currentpos() {
+ return false;
+ }
+
+ // returns length of entire stream (limit for seekto()s)
+ function length() {
+ return false;
+ }
+}
+
+class StringReader {
+ var $_pos;
+ var $_str;
+
+ function StringReader($str='') {
+ $this->_str = $str;
+ $this->_pos = 0;
+ // If string functions are overloaded, we need to use the mb versions
+ $this->is_overloaded = ((ini_get("mbstring.func_overload") & 2) != 0) && function_exists('mb_substr');
+ }
+
+ function _substr($string, $start, $length) {
+ if ($this->is_overloaded) {
+ return mb_substr($string,$start,$length,'ascii');
+ } else {
+ return substr($string,$start,$length);
+ }
+ }
+
+ function _strlen($string) {
+ if ($this->is_overloaded) {
+ return mb_strlen($string,'ascii');
+ } else {
+ return strlen($string);
+ }
+ }
+
+ function read($bytes) {
+ $data = $this->_substr($this->_str, $this->_pos, $bytes);
+ $this->_pos += $bytes;
+ if ($this->_strlen($this->_str)<$this->_pos)
+ $this->_pos = $this->_strlen($this->_str);
+
+ return $data;
+ }
+
+ function seekto($pos) {
+ $this->_pos = $pos;
+ if ($this->_strlen($this->_str)<$this->_pos)
+ $this->_pos = $this->_strlen($this->_str);
+ return $this->_pos;
+ }
+
+ function currentpos() {
+ return $this->_pos;
+ }
+
+ function length() {
+ return $this->_strlen($this->_str);
+ }
+}
+
+
+class FileReader {
+ var $_pos;
+ var $_fd;
+ var $_length;
+
+ function FileReader($filename) {
+ if (file_exists($filename)) {
+
+ $this->_length=filesize($filename);
+ $this->_pos = 0;
+ $this->_fd = fopen($filename,'rb');
+ if (!$this->_fd) {
+ $this->error = 3; // Cannot read file, probably permissions
+ return false;
+ }
+ } else {
+ $this->error = 2; // File doesn't exist
+ return false;
+ }
+ }
+
+ function read($bytes) {
+ if ($bytes) {
+ fseek($this->_fd, $this->_pos);
+
+ // PHP 5.1.1 does not read more than 8192 bytes in one fread()
+ // the discussions at PHP Bugs suggest it's the intended behaviour
+ while ($bytes > 0) {
+ $chunk = fread($this->_fd, $bytes);
+ $data .= $chunk;
+ $bytes -= strlen($chunk);
+ }
+ $this->_pos = ftell($this->_fd);
+
+ return $data;
+ } else return '';
+ }
+
+ function seekto($pos) {
+ fseek($this->_fd, $pos);
+ $this->_pos = ftell($this->_fd);
+ return $this->_pos;
+ }
+
+ function currentpos() {
+ return $this->_pos;
+ }
+
+ function length() {
+ return $this->_length;
+ }
+
+ function close() {
+ fclose($this->_fd);
+ }
+
+}
+
+// Preloads entire file in memory first, then creates a StringReader
+// over it (it assumes knowledge of StringReader internals)
+class CachedFileReader extends StringReader {
+ function CachedFileReader($filename) {
+ parent::StringReader();
+
+ if (file_exists($filename)) {
+
+ $length=filesize($filename);
+ $fd = fopen($filename,'rb');
+
+ if (!$fd) {
+ $this->error = 3; // Cannot read file, probably permissions
+ return false;
+ }
+ $this->_str = fread($fd, $length);
+ fclose($fd);
+
+ } else {
+ $this->error = 2; // File doesn't exist
+ return false;
+ }
+ }
+}
+
+
+?>
diff --git a/tighturl-base10 b/tighturl-base10
new file mode 100755
index 0000000..6432e04
--- /dev/null
+++ b/tighturl-base10
@@ -0,0 +1,5 @@
+#!/usr/bin/php
+
diff --git a/tighturl-base10.php b/tighturl-base10.php
new file mode 100644
index 0000000..74f70bc
--- /dev/null
+++ b/tighturl-base10.php
@@ -0,0 +1,22 @@
+
+
+TightURL ID converter
+
+
+TightURLID(Base-36): ".$_POST[id]."
DBID(decimal): ".base_convert($_POST[id], 36, 10)."\n";
+}
+else
+{
+?>
+
+
+
+
diff --git a/tighturl-base36 b/tighturl-base36
new file mode 100755
index 0000000..c8b2c3d
--- /dev/null
+++ b/tighturl-base36
@@ -0,0 +1,5 @@
+#!/usr/bin/php
+
diff --git a/tighturl-base36.php b/tighturl-base36.php
new file mode 100644
index 0000000..8e4a176
--- /dev/null
+++ b/tighturl-base36.php
@@ -0,0 +1,22 @@
+
+
+Convert base 10 to TightURL ID
+
+
+Base-10(decimal): ".$_POST[decimal]."
TightURL ID(base-36): ".base_convert($_POST[decimal], 10, 36)."\n";
+}
+else
+{
+?>
+
+
+
+
diff --git a/tighturl-install.php b/tighturl-install.php
new file mode 100644
index 0000000..f1468c9
--- /dev/null
+++ b/tighturl-install.php
@@ -0,0 +1,133 @@
+
+
+
+
+ TightURL Installer
+
+
+
+Finished.
+
+Your TightURL database has been installed or upgraded as appropriate.
+
+You must delete (or at least rename) tighturl-install.php in order to run TightURL.
+
+
+
+
+
+
+
+
+
+ TightURL Install/Upgrade
+
+
+Welcome to the TightURL Installer and Upgrader
+
+This script will either set up a newly created TightURL database, or upgrade an existing TightURL database
+to work with the version of TightURL you just installed. This process will happen automatically once you click
+the "install/upgrade now!" button below.
+
+Before starting, please make sure you've completed the following steps below:
+
+ - BACK UP your TightURL database!!!!
+ - Make sure
tighturl.config.inc.php has the proper settings for
+ $dbhost, $dbname, $dbtable,
+ $dbuser, and $dbpass.
+
+
+
+
+
+
+
+
+\n \n TightURL Installer/Upgrader\n \n \n";
+ echo " " . $errmsg . "
\n";
+ echo " \n";
+ die;
+}
+
+?>
diff --git a/tighturl-killbot.php b/tighturl-killbot.php
new file mode 100755
index 0000000..904bab7
--- /dev/null
+++ b/tighturl-killbot.php
@@ -0,0 +1,27 @@
+#!/usr/bin/php
+= ".REQUIRED_PHP_VERSION." (you are using ".phpversion().")");
+ }
+
+ if (file_exists("tighturl.tltpattern.inc.php")) include("tighturl.tltpattern.inc.php");
+ if (file_exists("tighturl.urlpattern.inc.php")) include("tighturl.urlpattern.inc.php");
+ if (file_exists("tighturl.ptcpattern.inc.php")) include("tighturl.ptcpattern.inc.php");
+ if (file_exists("tighturl.blippattern.inc.php")) include("tighturl.blippattern.inc.php");
+ (include("tighturl.lib.inc.php")) or die("Error: cannot load tighturl.lib.inc.php");
+ if (file_exists("tighturl.config.inc.php")) include("tighturl.config.inc.php");
+
+ // Connect to MySQL, open database.
+ $conn = @mysql_connect($dbhost, $dbuser, $dbpass) or die("Error: Cannot connect to database.");
+ $db = mysql_select_db($dbname, $conn) or die("Error: Cannot select database. ". mysql_error());
+
+ // Query records with status normal, and added within last 10 days or records with status normal and more than 7 hits and hit within the last 7 days
+ TightURL_KillBot("SELECT * FROM $dbtable where status=0 && (DATE_SUB(CURDATE(), INTERVAL 10 DAY) <= adddate || (hits > 7 && DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= lasthit)) ORDER BY id;");
+ TightURL_NewReport("SELECT * FROM $dbtable where (status=0) && (checkcount < 2) ORDER BY id;");
+ exit;
+
+?>
diff --git a/tighturl.blacklist.tmpl b/tighturl.blacklist.tmpl
new file mode 100644
index 0000000..69f2931
--- /dev/null
+++ b/tighturl.blacklist.tmpl
@@ -0,0 +1,5 @@
+ The $SVCNAME redirection URL you have requested has been disabled due to
+ its appearance on one or more of the URI blacklists this site has used to
+ detect abuse, including spamming and phishing abuse.
+
+ Most likely it was listed on one of the following URI Blacklists: $URIBLS .
diff --git a/tighturl.blippattern.inc.php b/tighturl.blippattern.inc.php
new file mode 100644
index 0000000..851216d
--- /dev/null
+++ b/tighturl.blippattern.inc.php
@@ -0,0 +1,4 @@
+
diff --git a/tighturl.blpattern.inc.php b/tighturl.blpattern.inc.php
new file mode 100644
index 0000000..b113546
--- /dev/null
+++ b/tighturl.blpattern.inc.php
@@ -0,0 +1,19 @@
+
diff --git a/tighturl.complaints.tmpl b/tighturl.complaints.tmpl
new file mode 100644
index 0000000..6a4e5b3
--- /dev/null
+++ b/tighturl.complaints.tmpl
@@ -0,0 +1,2 @@
+ The $SVCNAME redirection URL you have requested has been disabled due to
+ excessive abuse complaints.
diff --git a/tighturl.lib.inc.php b/tighturl.lib.inc.php
new file mode 100644
index 0000000..18f6f91
--- /dev/null
+++ b/tighturl.lib.inc.php
@@ -0,0 +1,287 @@
+= ".REQUIRED_PHP_VERSION." (you are using ".phpversion().")");
+ }
+
+
+$validipv4pattern = "/^(http|https|ftp|sftp):\/\/(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.";
+$validipv4pattern .= "(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])";
+$validipv4pattern .= "\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\/*/";
+
+// ****** !All overridable configuration variables must go above this line! ******
+
+function TightURL_version_check() {
+ global $VUCycle;
+
+ // check http://tighturl.com/version.php and/or http://tighturl.sf.net/version.php
+ // parse out if there's a security release
+ // notify admin of this tighturl installation once if there's a new version,
+ // once a week, if there's a security fix.
+ // Possibly display "newer version available" on templates.
+ // Possibly disable vulnerable versions after a certain amount of time.
+ // ie, only show "Site down for emergency maintenance. If you are the administrator, click here."
+ // validate against mysql database password, show vulnerability screen.
+
+ if ($VUCycle < 24) $VUCycle = 24; // someone's trying to get banned.
+}
+
+/**
+ * Checks accepted URLs against URI blacklists and marks listed URLs as abused.
+ */
+function TightURL_KillBot($query='') {
+
+ global $dbtable;
+
+ if ($query == "") $query="SELECT * FROM $dbtable;";
+
+ // Query records with status normal, and added within last 2 weeks or records with status normal and more than 7 hits and hit within the last 2 weeks
+ // "SELECT * FROM $dbtable where status=0 && (DATE_SUB(CURDATE(), INTERVAL 14 DAY) <= adddate || (hits > 7 && DATE_SUB(CURDATE(), INTERVAL 14 DAY) <= lasthit)) ORDER BY id;"
+ $set = mysql_query($query);
+ $rows = @mysql_num_rows($set) or $rows = 0;
+
+ for ($i = 0; $i <$rows; $i++) {
+
+ $row = mysql_fetch_array($set);
+ $id = $row["id"];
+ $url = $row["url"];
+ $status = $row["status"];
+ $hits = $row["hits"];
+
+ $hit = URI_on_URIBL($url);
+ if ($hit) {
+ // Change this to disable instead of delete, delete at some future point.
+ $req ="update $dbtable set status=3 where id='$id';";
+ $res = mysql_query($req);
+ }
+// elseif ($hits > 4000) {
+// // Change this to disable instead of delete, delete at some future point.
+// $req ="update $dbtable set status=5 where id='$id';";
+// $res = mysql_query($req);
+// }
+ else {
+ $req = "update $dbtable set lastcheck=NOW(), checkcount=checkcount+1 where id='$id';";
+ $res = mysql_query($req);
+ }
+ }
+}
+
+function TightURL_NewReport($query='') {
+
+ global $dbtable;
+
+ if ($query == "") $query="SELECT * FROM $dbtable;";
+
+ $set = mysql_query($query);
+ $rows = @mysql_num_rows($set) or $rows = 0;
+
+ if ($rows > 0) {
+ $MP = "/usr/sbin/sendmail -t ron@vnetworx.net";
+ $fd = popen($MP, "w");
+ fputs($fd, "To: ron@vnetworx.net\n");
+ fputs($fd, "From: killbot@tighturl.com \n");
+ fputs($fd, "Subject: TightURL additions report\n");
+ fputs($fd, "\n");
+
+ for ($i = 0; $i <$rows; $i++) {
+ $row = mysql_fetch_array($set);
+ $id = $row["id"];
+ $url = $row["url"];
+ fputs($fd, "Block: http://tighturl.com/?p=" . base_convert($id, 10, 36) . " URL: $url\n\n");
+ }
+ pclose($fd);
+ }
+}
+
+/**
+ * Checks to see if a given URI is on a URI blacklist.
+ * Currently this means SURBL (http://www.surbl.org) and URIBL (http://www.uribl.com)
+ *
+ * Returns TRUE if the domain is listed on any configured URIBLs.
+ *
+ * A companion URI extractor must be written for the below issues
+ * Must be changed to do full resolution of redirections on URI, simulating a browser
+ * Must be changed to do IPv6 lookups
+ * Must be changed to check multiple URIs
+ * Must be changed to optionally check HTML entity encoded versions of URIs
+ * Must be changed to handle URIBL's inclusion of some third-level domains.
+ *
+ */
+function URI_on_URIBL($uri) {
+
+// This code does not yet properly implement a correct and efficient querying
+// of URI BL data.
+
+ global $uribl, $uribluri, $validurlpattern, $validipv4pattern, $tltlds, $validschemes;
+
+ $uribls = "";
+
+ if ($uri) {
+ // Test for IPv4 address, reverse the quads if found
+ if (preg_match($validipv4pattern,$uri,$matches)) {
+ $domain=$matches[5] . "." . $matches[4] . "." . $matches[3] . "." . $matches[2];
+ }
+ else {
+ // strip out second-level domain name, *unless* on exception list,
+ // in which case, strip out third level also and test that instead.
+ preg_match("/^".$validschemes.$validurlpattern."$/", $uri, $matches);
+ //preg_match($validurlpattern, $uri, $matches);
+ $domain = $matches[4];
+ if (preg_match("/".$tltlds."$/", $domain, $matches)) {$levels = 2;} else {$levels = 1;}
+ //if (preg_match($tltlds, $domain, $matches)) {$levels = 2;} else {$levels = 1;}
+
+ // klugey stripping routine to reduce domain to base domain name
+ // expect regex wojuld be better
+// (.*\..*){2} matches vnetworx.co.uk but not vnetworx.com
+// .*(\.co\.uk) matches[1] .co.uk
+
+ $ss = countSubstrs($domain, ".");
+ while ($ss > $levels) {
+ $chop = strpos($domain, ".");
+ $domain = substr($domain, $chop + 1);
+ $ss = countSubstrs($domain, ".");
+ }
+ }
+
+ // Query URI blacklists to see if domain/IP appears as target in known spam
+ // or something involved in a malware/phishing attack.
+ for ($i=0; $i 0) $uribls .= ", ";
+ $uribls .= $uribl[$i];
+ }
+ }
+ if ($uribls) return $uribls; else return FALSE; // change to return an array of indexes into the URIBL array
+ }
+}
+
+/**
+ * Checks to see if a given URL is a Reserved URL.
+ *
+ * Returns TRUE if the ID is listed as a Reserved URL.
+ */
+function on_Reserve($decimal) {
+ global $ReservedURL;
+
+ $res=FALSE;
+
+ if ($decimal) {
+ $sexatrigesimal = base_convert($decimal, 10, 36);
+ for ($i=0; $i $v2[0]) $ret = 1;
+ elseif ($v1[0] < $v2[0]) $ret = -1;
+ else {
+ // Major version numbers are equal
+ if ($v1[1] > $v2[1]) $ret = 1;
+ elseif ($v1[1] < $v2[1]) $ret = -1;
+ else {
+ // Minor version numbers are equal
+ if ($v1[2] > $v2[2]) $ret = 1;
+ elseif ($v1[2] < $v2[2]) $ret = -1;
+ else $ret = 0;
+ }
+ }
+ return $ret;
+ }
+}
+
+/**
+ * Add in file_get_contents for PHP < 4.3.0
+ */
+if (! function_exists('file_get_contents')) {
+ function file_get_contents($filename, $incpath = false, $resource_context = null)
+ {
+ if (false === $fh = fopen($filename, 'rb', $incpath)) {
+ trigger_error('file_get_contents() failed to open stream: No such file or directory', E_USER_WARNING);
+ return false;
+ }
+ clearstatcache();
+ if ($fsize = @filesize($filename)) $data = fread($fh, $fsize);
+ else {
+ $data = '';
+ while (!feof($fh)) $data .= fread($fh, 8192);
+ }
+ fclose($fh);
+ return $data;
+ }
+}
+
+?>
diff --git a/tighturl.php b/tighturl.php
new file mode 100644
index 0000000..f2fd10d
--- /dev/null
+++ b/tighturl.php
@@ -0,0 +1,757 @@
+
+ * portions Copyright (c) 2002,2003 Free Software Foundation
+ *
+ * This file implements a blind redirection service named TightURL.
+ * TightURL is Free Software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * TightURL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * If you are not able to view the LICENSE, which should
+ * always be possible within a valid and working TightURL release,
+ * please write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * to get a copy of the GNU General Public License or to report a
+ * possible license violation.
+ *
+ * @package TightURL
+ * @author Ron Guerin
+ * @license http://www.fsf.org/licenses/gpl.html GNU Public License
+ * @copyright Copyright © 2004-2009 Ron Guerin
+ * @filesource
+ * @link http://tighturl.com TightURL
+ * @version 0.1.4
+ *
+ */
+
+define("VERSION", "0.1.4");
+define("REQUIRED_PHP_VERSION", "4.3.0");
+
+// System defaults, DO NOT EDIT THIS FILE
+// Edit tighturl.config.inc.php instead!
+
+global $copyright, $conn, $db, $os, $svcname;
+
+$dbhost = "localhost";
+$dbuser = "dbuser";
+$dbpass = "dbpass";
+$dbname = "tighturl";
+$dbtable = "urls";
+$FOFMethod=FALSE; //0=Full URL path or mod_rewrite, 1=404-Method compressed URLs
+$os="";
+
+// URIBL variables
+$uribl = array("multi.surbl.org", "black.uribl.com");
+$uriblurl = array("www.surbl.org", "www.uribl.com");
+
+// Bad Behavior variables
+$BB2 = true;
+$BBstats = true;
+$BBstrict = false;
+$BBverbose = true;
+$BBLogging = true;
+$bb2_settings_defaults = "";
+
+// Require submitted URLs to exist?
+$mustexist = true;
+
+// Text strings and style variables
+$svcname = "URLSquisher";
+$verbtext = "Squish";
+$pasttext = "Squished";
+$tagline = "Squish long URLs to make short ones";
+$headcolor = "#006600";
+$tablecolor = "#00CC99";
+$copystart = date("Y");
+$copyrightholder = "SquishURL Enterprises";
+
+// Reserved URLs
+$ReservedURL = array("x", "rest", "xmlrpc", "soap", "xml", "atom", "rss", "blog",
+ "faq", "help", "about", "api", "code", "source", "docs",
+ "git", "cvs", "arch", "url", "admin", "setup", "svn", "project",
+ "abuse", "cgi-sys", "exploited");
+
+// You REALLY don't want to edit below here unless you know what you're doing.
+
+// *************************************************************************
+
+ if (version_compare(phpversion(), REQUIRED_PHP_VERSION)<0) {
+ die_HTML($svcname, "Error: TightURL ".VERSION." needs PHP >= ".REQUIRED_PHP_VERSION." (you are using ".phpversion().")");
+ }
+
+ if (file_exists("tighturl-install.php")) die_HTML($svcname, "Error: You must remove tighturl-install.php before using $svcname.");
+
+ $os=strpos(strtolower(PHP_OS), "win")===false?"nix":"win";
+
+ $validurlpattern = "\:\/\/([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)"
+ . "*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])"
+ . "\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)"
+ . "\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)"
+ . "\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])"
+ . "|((([0-9A-F]{1,4}(((:[0-9A-F]{1,4}){5}::[0-9A-F]{1,4})|((:[0-9A-F]{1,4}){4}"
+ . "::[0-9A-F]{1,4}(:[0-9A-F]{1,4}){0,1})|((:[0-9A-F]{1,4}){3}::[0-9A-F]{1,4}"
+ . "(:[0-9A-F]{1,4}){0,2})|((:[0-9A-F]{1,4}){2}::[0-9A-F]{1,4}(:[0-9A-F]{1,4})"
+ . "{0,3})|(:[0-9A-F]{1,4}::[0-9A-F]{1,4}(:[0-9A-F]{1,4}){0,4})|(::[0-9A-F]{1,4}"
+ . "(:[0-9A-F]{1,4}){0,5})|(:[0-9A-F]{1,4}){7}))|(::[0-9A-F]{1,4}(:[0-9A-F]{1,4}"
+ . "){0,6}))|::)|((([0-9A-F]{1,4}(((:[0-9A-F]{1,4}){3}::([0-9A-F]{1,4}){1})"
+ . "|((:[0-9A-F]{1,4}){2}::[0-9A-F]{1,4}(:[0-9A-F]{1,4}){0,1})|((:[0-9A-F]{1,4})"
+ . "{1}::[0-9A-F]{1,4}(:[0-9A-F]{1,4}){0,2})|(::[0-9A-F]{1,4}(:[0-9A-F]{1,4}"
+ . "){0,3})|((:[0-9A-F]{1,4}){0,5})))|([:]{2}[0-9A-F]{1,4}(:[0-9A-F]{1,4}){0,4}))"
+ . ":|::)((25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{0,2})\.){3}(25[0-5]|2[0-4][0-9]|"
+ . "[0-1]?[0-9]{0,2})"
+ . "|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org"
+ . "|mobi|biz|arpa|info|name|pro|aero|coop|museum"
+ . "|[a-zA-Z]{2}))(\:[0-9]+)*(\/.($|[a-zA-Z0-9\.\:\,\?\'\(\)\\\*\+&%\$;|#\=~_\-\s@]*))*\/*";
+
+ $validipv4pattern = ":\/\/(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\."
+ . "(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])"
+ . "\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\/*";
+
+ $forbid = "\.(cmd|bat|exe|scr|pif|vbs|js|pif|msi|cdr)";
+
+// ****** !All overridable configuration variables must go above this line! ******
+
+ if (! isset($antiabuse)) $antiabuse = true;
+ if (! isset($netchecks)) $netchecks = true;
+ if (! isset($mustexist)) $mustexist = true;
+
+ // Status: 0=Ok, 1=Warn, 2=Black, 3=Policy, 4=Complaints
+
+ if (file_exists("tighturl.urlpattern.inc.php")) include("tighturl.urlpattern.inc.php");
+ if (file_exists("tighturl.tltpattern.inc.php")) include("tighturl.tltpattern.inc.php");
+ if (file_exists("tighturl.redirpattern.inc.php")) include("tighturl.redirpattern.inc.php");
+ if (file_exists("tighturl.ptcpattern.inc.php")) include("tighturl.ptcpattern.inc.php");
+ if (file_exists("tighturl.blpattern.inc.php")) include("tighturl.blpattern.inc.php");
+ if (file_exists("tighturl.config.inc.php")) include("tighturl.config.inc.php");
+
+ // Figure out our copyright string
+ $thisyear = date("Y");
+ $copyright = $copystart;
+ if ($copystart != $thisyear) $copyright .= "-" . $thisyear;
+ $uribls = "";
+ for ($i=0; $i 0) $uribls .= ", ";
+ $uribls .= "" . $uribl[$i] . "";
+ }
+
+ if (! $FOFMethod) $parm = "?i="; // We need the parameter tag
+
+ // Figure out correct self
+ if (strncmp($_SERVER['PHP_SELF'], $_SERVER['REQUEST_URI'], strlen($_SERVER['PHP_SELF'])) != 0) {
+ if (preg_match("|(.*)/.*$|",$_SERVER['PHP_SELF'],$matches)) $self = $matches[1];
+ if (! preg_match("|.*/$|", $self)) $self .= "/";
+ }
+ else {
+ $self = $_SERVER['PHP_SELF']; // We need the script name
+ if (! preg_match("|.*/$|", $self)) $self .= "/";
+ }
+
+ // Connect to MySQL, open database.
+ $conn = @mysql_connect($dbhost, $dbuser, $dbpass) or die_HTML($svcname, "Error: Cannot connect to database.");
+ $db = mysql_select_db($dbname, $conn) or die_HTML($svcname, "Error: Cannot select database. ". mysql_error());
+
+ // When in doubt, turn Bad Behavior on, set it to FALSE in the config to turn it off.
+ if (! isset($BB2)) $BB2 = true;
+
+ // If user has not turned off Bad Behavior in the config, use BB2 (highly recommended) TODO: warn user if $BB2 but not BB2
+ if ($BB2 && file_exists("bad-behavior/bad-behavior-tighturl.php")) require_once("bad-behavior/bad-behavior-tighturl.php");
+ else $BB2 = FALSE;
+
+ // Figure out what kind of request this is and service it.
+
+ // This is klugey. Clean up later.
+ // also I think data should be sanitized immediately
+ if ((isset($_REQUEST['save']) && $_REQUEST['save'] == 'y')
+ && (isset($_REQUEST['url']) && ! empty($_REQUEST['url']) && trim($_REQUEST['url']) != ""
+ && (preg_match("/^.*url=(.*)$/", $_SERVER['QUERY_STRING'], $matches) != 0))) {
+ $url = trim($matches[1]);
+ if (preg_match("/^(.*)&tighturlaction.*$/", $matches[1], $matches)) $url = $matches[1];
+ save_URL(urldecode($url));
+ }
+ elseif (isset($_REQUEST['i']) && !empty($_REQUEST['i'])) {
+ lookup_ID($_REQUEST['i']);
+ }
+ elseif (isset($pbi) && !empty($pbi) && isset($_REQUEST[$pbi]) && !empty($_REQUEST[$pbi])) {
+ PolicyBan_ID($_REQUEST[$pbi]);
+ }
+ elseif ($FOFMethod && preg_match("/^\/+([a-zA-Z0-9]+)\/*(.*)\/*$/", $_SERVER['REQUEST_URI'], $matches)) {
+ lookup_ID($matches[1]);
+ }
+ elseif ($FOFMethod && $_SERVER['REQUEST_URI'] != "/") {
+ display_HTML("", "", "Error: Couldn't find a valid " . $svcname . " URI.");
+ }
+ else {
+ display_HTML("", "main");
+ }
+ exit;
+
+// *************************************************************************
+
+
+/**
+ * sanitize a string for SQL input
+ */
+function sanitize_sql_string($string) {
+ return(mysql_real_escape_string($string));
+}
+
+/**
+ * Counts the number of times a substring is contained in a given string.
+ */
+function countSubstrs($haystack, $needle) {
+ return (($p = strpos($haystack, $needle)) === false) ? 0 : (1 + countSubstrs(substr($haystack, $p+1), $needle));
+}
+
+/**
+ * Checks to see if a given URI is on a URI blacklist.
+ * Currently this means SURBL (http://www.surbl.org) and URIBL (http://www.uribl.com)
+ *
+ * Returns TRUE if the domain is listed on any configured URIBLs, returns FALSE if
+ * anything goes wrong or the anti-abuse system is turned off.
+ *
+ * A companion URI extractor must be written for the below issues
+ * Must be changed to do full resolution of redirections on URI, simulating a browser
+ * Must be changed to do IPv6 lookups
+ * Must be changed to check multiple URIs (maybe a wrapper instead)
+ * Must be changed to optionally check HTML entity encoded versions of URIs
+ * Must be changed to handle URIBL's inclusion of some third-level domains.
+ *
+ */
+function URI_on_URIBL($uri) {
+
+// This code does not yet properly implement a correct and efficient querying
+// of URI BL data.
+
+ global $uribl, $uribluri, $validschemes, $validurlpattern, $validipv4pattern,
+ $antiabuse, $netchecks, $tltlds;
+
+ // Everything gets a pass if antiabuse or network tests are off.
+ if ((! $antiabuse) || (! $netchecks)) return(false);
+
+ $uribls = "";
+
+ if ($uri) {
+ // Test for IPv4 address, reverse the quads if found
+ if (preg_match("/^".$validschemes.$validipv4pattern."/", $uri, $matches)) {
+ $domain=$matches[5] . "." . $matches[4] . "." . $matches[3] . "." . $matches[2];
+ }
+ else {
+ // strip out second-level domain name, *unless* on exception list,
+ // in which case, strip out third level also and test that instead.
+ // FIX: when testing uribl.com lists, also test additional level. First hit wins.
+
+ preg_match("/^".$validschemes.$validurlpattern."$/", $uri, $matches);
+ $domain = $matches[4];
+ if (preg_match("/".$tltlds."$/", $domain, $matches)) {$levels = 2;} else {$levels = 1;}
+
+ // klugey stripping routine to reduce domain to base domain name
+ // expect regex wojuld be better
+
+ $ss = countSubstrs($domain, ".");
+ while ($ss > $levels) {
+ $chop = strpos($domain, ".");
+ $domain = substr($domain, $chop + 1);
+ $ss = countSubstrs($domain, ".");
+ }
+ }
+
+ // Query URI blacklists to see if domain/IP appears as target in known spam
+ // or something involved in a malware/phishing attack.
+ for ($i=0; $i", $recexists)) {
+ if ($i > 0) $uribls .= ", ";
+ $uribls .= $uribl[$i];
+ }
+ }
+ return ($uribls); // change to return an array of indexes into the URIBL array
+ }
+}
+
+/**
+ * Checks to see if a given URL is a Reserved URL.
+ *
+ * Returns TRUE if the ID is listed as a Reserved URL.
+ */
+function on_Reserve($decimal) {
+ global $ReservedURL;
+
+ $res=FALSE;
+
+ if ($decimal) {
+ $sexatrigesimal = base_convert($decimal, 10, 36);
+ for ($i=0; $ii", $url)) {
+ display_HTML("", "", "Error: ".$svcname." is not a URL obfuscation service, and does not accept redirection links.", $url, "", $url);
+ }
+ elseif (isset($ptc) && preg_match("/.*".$ptc.".*/i", $url)) {
+ display_HTML("", "", "Error: ".$svcname." does not accept PTC (Pay To Click) links due to spamming abuse.", $url, "", $url);
+ }
+ else {
+ $safeurl = sanitize_sql_string($url);
+ $result = mysql_query("SELECT MAX(id) FROM $dbtable") or display_HTML("", "", "Error: $svcname system error.", $url, "", $url);
+ $lastid = mysql_result($result, 0) + 1;
+ $guesssexatrigesimal = base_convert($lastid, 10, 36);
+ $guessurl = "http://" . $_SERVER['HTTP_HOST'] . $self;
+ if (! $FOFMethod) $guessurl .= "?i="; // We need the parameter tag
+ $guessurl .= $guesssexatrigesimal; // Append the Base-36 ID to the URL
+ if ( strlen($guessurl) >= strlen($url) ) {
+ display_HTML("", "", "Fail: That URL cannot be shortened by $svcname. Sorry!", $url, "", $url);
+ }
+ else {
+ if ($antiabuse && $netchecks) {$lists = URI_on_URIBL($url);} else {$lists = false;}
+ if (! $lists) {
+ $rows=0; $srows=0; $testurl=$safeurl;
+ if (preg_match("/\/$/", $testurl)) $testurl = rtrim($testurl,"/");
+ $req = "SELECT * FROM $dbtable WHERE url = '$testurl/';";
+ $res = mysql_query($req);
+ $srows = @mysql_num_rows($res) or $srows = 0;
+ if ($srows == 0) {
+ $req = "SELECT * FROM $dbtable WHERE url = '$testurl';";
+ $res = mysql_query($req);
+ $rows = @mysql_num_rows($res) or $rows = 0;
+ }
+ if ($rows == 0 && $srows == 0) {
+ do {
+ $req ="INSERT INTO $dbtable (id, url, adddate, addip) ";
+ $req .= "VALUES ('', '$safeurl', NOW(), '$remote');";
+ if (mysql_query($req)) {
+ $decimal = mysql_insert_id();
+ }
+ else {
+ die_HTML($svcname, "Error: Database failure.");
+ }
+ $reserved_id = on_Reserve($decimal);
+ if ($reserved_id) {
+ // Delete this record so it doesn't override the reserved ID. (?)
+ $req = "DELETE FROM $dbtable WHERE id = '$decimal';";
+ $res = mysql_query($req) or die_HTML($svcname, "Error: Database failure.");
+ }
+ } while ($reserved_id);
+ }
+ else {
+ // Return existing ID for this duplicate request
+ $decimal = mysql_result($res, 0, "id");
+ }
+ $sexatrigesimal = base_convert($decimal, 10, 36);
+ $address = "http://" . $_SERVER['HTTP_HOST'] . $self;
+ if (! $FOFMethod) $address .= "?i="; // We need the parameter tag
+ $address .= $sexatrigesimal; // Append the Base-36 ID to the URL
+ display_HTML("", "save", "", $url, $address);
+ }
+ else {
+ display_HTML("HTTP/1.0 403 Forbidden", "", "Error: Submitted URL (" . $url . ") is listed in " . $lists . ". You may not create a " . $svcname . " link for it.");
+ }
+ }
+ }
+}
+
+/**
+ *
+ */
+function PolicyBan_ID($sexatrigesimal) {
+ global $dbtable, $svcname;
+
+ // First, convert unsafe user input sexatrigesimal to decimal, which will be safe.
+ $decimal = base_convert ($sexatrigesimal, 36, 10);
+
+ $req = "SELECT * FROM $dbtable WHERE id = '$decimal';";
+ $res = mysql_query($req) or die_HTML($svcname, "Error: Query failed");
+
+ $rows = mysql_num_rows($res);
+ if (($rows != 0) && (mysql_result($res, 0, "url") != "")) {
+ $req ="update $dbtable set status='4' where id='$decimal';";
+ $res = mysql_query($req);
+ die_HTML($svcname, "ID: " . $sexatrigesimal . " banned for policy violation.", $code="HTTP/1.0 200 OK");
+ }
+}
+
+/**
+ * Looks up given ID in the database and redirects, displays template, or
+ * displays error page. Expects the ID to be a sexatrigesimal (Base-36) number,
+ * which is the format used by TightURLs.
+ *
+ * We convert the ID to decimal before looking it up in the database, as the
+ * ID field is a MySQL autoincrement decimal value.
+ */
+function lookup_ID($sexatrigesimal) {
+ global $dbtable, $svcname;
+
+ // First, convert unsafe user input sexatrigesimal to decimal, which will be safe.
+ $decimal = base_convert ($sexatrigesimal, 36, 10);
+
+ $req = "SELECT * FROM $dbtable WHERE id = '$decimal';";
+ $res = mysql_query($req) or die_HTML($svcname, "Error: Query failed");
+
+ $rows = mysql_num_rows($res);
+ if (($rows != 0) && (mysql_result($res, 0, "url") != "")) {
+ // Change this logic to display a templated page instead?
+ switch (mysql_result($res, 0, "status")) {
+ case 5:
+ display_HTML("HTTP/1.0 403 Forbidden", "complaints");
+ return;
+ break;
+ case 4:
+ display_HTML("HTTP/1.0 403 Forbidden", "policy");
+ return;
+ break;
+ case 3:
+ display_HTML("HTTP/1.0 403 Forbidden", "blacklist");
+ return;
+ break;
+ default:
+ $url = stripslashes(mysql_result($res, 0, "url"));
+ break;
+ }
+ $req ="update $dbtable set lasthit=NOW(), hits=hits+1 where id='$decimal';";
+ $res = mysql_query($req);
+ header("HTTP/1.0 301 Moved Permanently");
+ header("Location: $url");
+ }
+ elseif (! on_Reserve($decimal)) { // Not found, Not on reserve
+ display_HTML("HTTP/1.0 404 Not Found", "", "Error: That " . $svcname . " ID is not in our database.");
+ }
+ else { // It's a(n implied) Reserved URL
+ // Is this a template or an API?
+ $sexatrigesimal = strtolower($sexatrigesimal);
+ switch ($sexatrigesimal) {
+ case "rest":
+ api_REST();
+ break;
+ case "xmlrpc":
+ api_XMLRPC();
+ break;
+ case "soap":
+ api_SOAP();
+ break;
+ default:
+ display_HTML("", $sexatrigesimal);
+ }
+ }
+}
+
+function api_REST() {
+ die_HTML($svcname, "Error: REST API not implemented yet.", "HTTP/1.0 501 Not Implemented");
+}
+
+function api_XMLRPC() {
+ die_HTML($svcname, "Error: XML-RPC API not implemented yet.", "HTTP/1.0 501 Not Implemented");
+}
+
+function api_SOAP() {
+ die_HTML($svcname, "Error: SOAP API not implemented yet.", "HTTP/1.0 501 Not Implemented");
+}
+
+/**
+ * Display HTML page using template and template variables.
+ *
+ * Reads in the main system template file (tighturl.tmpl) into $html .
+ *
+ * $code
+ * HTTP 1.0 status code and message.
+ *
+ * $template
+ * Checks for the existence of a subtemplate named tighturl.$template.tmpl
+ * and replaces template variable $HTML in the main template tighturl.tmpl
+ * with the contents of tighturl.$template.tmpl if any.
+ *
+ * Then any remaining $HTML from the only or inner template is replaced by $content,
+ * along with $url, $tighturl, and $input. A variety of other replacements are
+ * made using various global variables.
+ *
+ * $content
+ * HTML content to be replace template variable $HTML
+ *
+ * $url
+ * URL submitted to TightURL
+ *
+ * $tighturl
+ * TightURL generated for $url
+ *
+ * $input
+ * When submitted URL does not validate it is passed back as $input
+ *
+ * Template variables are words in all capital letters that start with a
+ * $ symbol, such as $TEMPLATEVARIABLE. TightURL now supports at least
+ * 20 template variables. At runtime, these template variables are replaced
+ * by program variables.
+ * - $HTML : HTML passed into the function as $input by the program or an inner template
+ * - $PARM : Parameter tag when not using 404-Method
+ * - $URL : URL submitted to TightURL
+ * - $URLLEN : Length of the submitted URL
+ * - $TIGHTURL : TightURL generated for the submitted URL
+ * - $TIGHTURLLEN : Length of generated TightURL
+ * - $DIFF : Difference in length between submitted and TightURLs
+ * - $INPUT : Bad input URL being passed back to output form
+ * - $SVCNAME : Name of the TightURL service
+ * - $HEADCOLOR : Color of the H1 Header tag
+ * - $TABLECOLOR : Color of the table containing URL input field
+ * - $TAGLINE : Tagline of the TightURL service
+ * - $CPASTTEXT : Capitalized past-tense word for tightening URLs
+ * - $PASTTEXT : Non-Capitalized past-tense word for tightening URLs
+ * - $CVERBTEXT : Capitalized action word for tightening URLs
+ * - $VERBTEXT : Non-Capitalized action word for tightening URLs
+ * - $COPYRIGHT : Copyright duration string generated from $copystart global variable,
+ * will be current 4-digit year if $copystart not defined.
+ * - $COPYRIGHTHOLDER : Name of copyright holder
+ * - $URLBLS : HTML string of URIBLs TightURL is checking
+ * - $HOST : Hostname TightURL is running on
+ * - $SELF : Name TightURL is invoked as
+ */
+function display_HTML ($code, $template, $content="", $url="", $tighturl="", $input="") {
+ global $svcname, $verbtext, $pasttext, $tagline, $uribls, $parm,
+ $headcolor, $tablecolor, $copyright, $copyrightholder, $self, $BB2;
+
+// $url = htmlspecialchars($url);
+ if ($code="") $code = "HTTP/1.0 200 OK";
+ if (preg_match("/\/$/", $template)) $template = rtrim($template,"/");
+ if (file_exists("tighturl.tmpl")) {
+ $html = file_get_contents("tighturl.tmpl");
+ if (($template != "") && file_exists("tighturl." . $template . ".tmpl")) {
+ $template = file_get_contents("tighturl." . $template . ".tmpl");
+ $html = preg_replace("/\\\$HTML/", $template, $html);
+ }
+ elseif ($template != "") {
+ die_HTML($svcname, "Error: Template file tighturl." . $template . ".tmpl cannot be found.");
+ }
+ if (substr($content, 0, 6) == "Error:") {
+ $content = preg_replace("/Error:/", "Error:", $content)."";
+ }
+ if ($content) $content .= "
\n";
+ // Always replace longer similar tokens before shorter ones. Things won't work the
+ // way you expect if you replace $URL first, and then replace $URLMORELETTERS.
+ $html = preg_replace("/\\\$HTML/", $content, $html);
+ $html = preg_replace("/\\\$PARM/", $parm, $html);
+ $html = preg_replace("/\\\$URLLEN/", strlen($url), $html);
+ $html = preg_replace("/\\\$URL/", htmlspecialchars(strip_tags($url), ENT_QUOTES), $html);
+ $html = preg_replace("/\\\$INPUT/", $input, $html);
+ $html = preg_replace("/\\\$TIGHTURLVER/", VERSION, $html);
+ $html = preg_replace("/\\\$TIGHTURLLEN/", strlen($tighturl), $html);
+ $html = preg_replace("/\\\$TIGHTURL/", $tighturl, $html);
+ $html = preg_replace("/\\\$DIFF/", strlen($url)-strlen($tighturl), $html);
+ $html = preg_replace("/\\\$SVCNAME/", $svcname, $html);
+ $html = preg_replace("/\\\$HEADCOLOR/", $headcolor, $html);
+ $html = preg_replace("/\\\$TABLECOLOR/", $tablecolor, $html);
+ $html = preg_replace("/\\\$TAGLINE/", $tagline, $html);
+ $html = preg_replace("/\\\$CPASTTEXT/", $pasttext, $html);
+ $html = preg_replace("/\\\$PASTTEXT/", strtolower($pasttext), $html);
+ $html = preg_replace("/\\\$VERBTEXT/", strtolower($verbtext), $html);
+ $html = preg_replace("/\\\$CVERBTEXT/", $verbtext, $html);
+ $html = preg_replace("/\\\$COPYRIGHTHOLDER/", $copyrightholder, $html);
+ $html = preg_replace("/\\\$COPYRIGHT/", $copyright, $html);
+ $html = preg_replace("/\\\$URIBLS/", $uribls, $html);
+ $html = preg_replace("/\\\$HOST/", $_SERVER['HTTP_HOST'], $html);
+ $html = preg_replace("/\\\$SELF/", $self, $html);
+ $html = preg_replace("/\\\$__/", "$", $html); // Template Variables shown as text instead of substituted
+ if (preg_match("|(.*)|is", $html, $matches))
+ $html = preg_replace("|(.*)|is", "" . strip_tags($matches[1]) . "", $html);
+ if ($BB2) {
+ $html = preg_replace("/\\\$BBSTATS/", bb2_insert_stats(), $html);
+ $bb2code = bb2_insert_head();
+ if (preg_match("|(.*)|is", $html, $matches))
+ $html = preg_replace("|(.*)|is", "\n" . $bb2code . $matches[1] . "", $html);
+ }
+ else {
+ $html = preg_replace("/\\\$BBSTATS/", "", $html);
+ }
+ header($code);
+ echo $html;
+ }
+ else {
+ die_HTML($svcname, "Error: Error: TightURL Redirection service (" . $svcname . ") site template not found.");
+ }
+}
+
+/**
+ * Die in an HTML-friendly way, without the benefit of a template.
+ * Use display_HTML to "die" using the TightURL site template.
+ */
+function die_HTML($svcname, $errmsg, $code="HTTP/1.0 500 Internal Server Error") {
+
+ header($code);
+ echo "\n \n " . $svcname . "\n \n \n";
+ echo " " . $errmsg . "
\n";
+ echo " \n";
+ die;
+}
+
+/**
+ * Verifies the existence and accessibility of a resource in a given URL.
+ *
+ * Returns FALSE if the resource does not exist or cannot be accessed using
+ * supplied authentication information, else returns the resolved and verified
+ * URL. Given URL is returned as resolved to itself if $netchecks are off.
+ *
+ * Will recurse through redirection chains up to 12 times by default. This
+ * value is preferably selectable by the user in a configuration screen
+ * somewhere, but probably should not be lower than 12, as attempts are made
+ * to detect HTML and JavaScript redirects in addition to HTTP redirects, and
+ * a dozen redirects to find the end is quite possible.
+ *
+ * Unfortunately Google's GFE server erroneously returns 404 errors when
+ * they should be returning something like a 405, making it impossible to
+ * use HTTP HEAD to verify the existence of resources front-ended by GFE.
+ * Additionally Amazon throws a 405 attempting to HEAD some of their resources
+ * so this function does not attempt to use HEAD at all.
+ *
+ * BUG: Presently only does HTTP
+ *
+ */
+//function Resolve_URL ($url, &$resolvedchain=array(""), $chainlen=12) {
+function Resolve_URL ($url, &$resolvedchain, $chainlen=12) {
+// $resolvedchain = array($url);
+
+ if (! isset($resolvedchain)) $resolvedchain=array("");
+
+ global $netchecks;
+
+ if (! $netchecks) {
+ // If network checks off, accept submitted URL as resolved.
+ return($url);
+ }
+
+ $parsed = parse_url($url);
+
+ $pre = isset($parsed['scheme']) ? $parsed['scheme'].':'.((strtolower($parsed['scheme']) == 'mailto') ? '' : '//') : '';
+ $pre .= isset($parsed['user']) ? $parsed['user'].(isset($parsed['pass']) ? ':'.$parsed['pass'] : '').'@' : '';
+ $pre .= isset($parsed['host']) ? $parsed['host'] : '';
+ $pre .= isset($parsed['port']) ? ':'.$parsed['port'] : '';
+ if(isset($parsed['path']))
+ $post = (substr($parsed['path'], 0, 1) == '/') ? $parsed['path'] : ('/'.$parsed['path']);
+ else
+ $post = "/";
+ $post .= isset($parsed['query']) ? '?'.$parsed['query'] : '';
+ $post .= isset($parsed['fragment']) ? '#'.$parsed['fragment'] : '';
+
+ $resolved = false;
+
+ // Change this to support all protocols TightURL supports, not just HTTP
+ if (! isset($parsed['port']) || $parsed['port'] == 0) $parsed['port'] = 80;
+//if($connection = @fsockopen ($parsed['host'], $parsed['port'], $errno, $errstr, 5)) {
+ $ip = gethostbyname($parsed['host']); // This is supposed to avoid unnecessary DNS lookups
+ if($connection = @fsockopen ($ip, $parsed['port'], $errno, $errstr, 5)) {
+ stream_set_timeout($connection, 5);
+ // HTTP send Connection: Close so we don't have to wait
+ // Google's GFE handling of HEAD is broken, and Amazon returns 405 on HEAD so had to use GET
+ fwrite($connection, "GET ".$post." HTTP/1.0\r\nHost: ".$parsed['host']."\r\nConnection: Close\r\n\r\n");
+ while (!feof($connection)) {
+ $line_read=fgets($connection);
+ if ($line_read == "") break; //blank line is header delimiter, if you see it you're done here
+ //Fix: change this and start parsing the body for HTML-based redirections.
+
+ if (preg_match("/HTTP\/\S* +(\S*) /", $line_read, $matches)) { // Look for certain HTTP status codes
+ switch ($matches[1]) {
+ case 200: // Ok, we have a final destination (as far as HTTP is concerned)
+ case 201: // Created, we have a final destination
+ case 202: // Accepted, we have a final destination
+ case 203: // Non-authoritative reply, we have a final destination
+ case 204: // No content, we have a final destination
+ case 205: // Reset content, we have a final destination
+ case 206: // Partial content, we have a final destination
+ case 207: // Multi-status, we have a final destination
+ case 304: // Not Modified (this is ok)
+ case 401: // Authorization required (this is ok)
+ case 402: // Payment required (this is ok)
+ case 403: // Forbidden (but also ok)
+ case 405: // Method not allowed (but also ok)
+ case 406: // Not acceptable (acceptable here unless someone tells us otherwise)
+ case 409: // Conflict (acceptable unless someone tells us otherwise)
+ case 421: // Too many connections (fail ok)
+ case 426: // Use TLS (fail ok)
+ case 500: // Internal server error (fail ok)
+ case 502: // Bad gateway (fail ok)
+ case 503: // Service unavailable (fail ok)
+ case 504: // Gateway timeout (fail ok)
+ case 505: // HTTP version not supported (fail ok)
+ case 509: // Bandwidth exceeded pseudo code (fail ok)
+ $resolved = $url;
+ $resolvedchain[] = $url;
+ break 2;
+ case 300:
+ case 301:
+ case 302:
+ case 307:
+ break;
+ case 404: // Not found
+ case 408: // Request timeout (this URL will never work again)
+ case 410: // Gone (and not coming back)
+ break 2;
+ default:
+ $resolved = $url;
+ $resolvedchain[] = $url;
+ break 2;
+ }
+ }
+
+ // If this is a redirect (300, 301, 302, 307), follow it if the chain isn't too long
+ if (preg_match("/Location: (.*)\r\n/", $line_read, $matches)) {
+ fclose($connection);
+ $connection = false;
+ $resolvedchain[] = $url;
+ if ($chainlen > 0 ) $resolved = Resolve_URL($matches[1], $resolvedchain, $chainlen - 1);
+ break;
+ }
+
+ }
+ // Parse body here?
+ if ($connection) fclose($connection);
+ }
+ return($resolved);
+}
+?>
diff --git a/tighturl.policy.tmpl b/tighturl.policy.tmpl
new file mode 100644
index 0000000..3182d33
--- /dev/null
+++ b/tighturl.policy.tmpl
@@ -0,0 +1,2 @@
+ The $SVCNAME redirection URL you have requested has been disabled due to
+ violations of $SVCNAME policy/Terms of Service.
diff --git a/tighturl.ptcpattern.inc.php b/tighturl.ptcpattern.inc.php
new file mode 100644
index 0000000..43c0893
--- /dev/null
+++ b/tighturl.ptcpattern.inc.php
@@ -0,0 +1,163 @@
+
diff --git a/tighturl.redirpattern.inc.php b/tighturl.redirpattern.inc.php
new file mode 100644
index 0000000..aabd1d0
--- /dev/null
+++ b/tighturl.redirpattern.inc.php
@@ -0,0 +1,118 @@
+
diff --git a/tighturl.tltpattern.inc.php b/tighturl.tltpattern.inc.php
new file mode 100644
index 0000000..5b32549
--- /dev/null
+++ b/tighturl.tltpattern.inc.php
@@ -0,0 +1,255 @@
+
diff --git a/tighturl.urlpattern.inc.php b/tighturl.urlpattern.inc.php
new file mode 100644
index 0000000..f833560
--- /dev/null
+++ b/tighturl.urlpattern.inc.php
@@ -0,0 +1,24 @@
+