<?php
/*
    This is a redirector script.

    Features:
    - Single file only
    - Does not needs a database
    - Does not needs write access
    - Encrypts links
    - Identical links will look different
    - Impossible to decrypt links without sending it to the server
    - Mobile compatible design
    - SafeBrowsing integration
    - API
    - Supports distributed deployment on server farms
    - Can be used standalone or as library

    Copyright © 2017 by /u/AyrA_ch

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    and associated documentation files (the "Software"), to deal in the Software without restriction,
    including without limitation the rights to use, copy, modify, merge, publish, distribute,
    sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    DISCLAIMER:
    THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
    THE POSSIBILITY OF SUCH DAMAGE.
*/

    //Version History
    //4.1 - Added AB_LIBRARY_ONLY for library exclusive usage
    //4.0 - Can now be used as a library
    //3.3 - MIT Licensed
    //3.2 - Shorter Base64 (no unnecessary padding anymore)
    //3.1 - CORS Support
    //3.0 - API Mode
    //2.1 - URL Hex format support
    //2.0 - Safebrowsing integration
    //1.1 - Optional IV setting
    //1.0 - Initial Version with encryption

    //CONFIG ===========================

        //The asterisk of a description indicates that changing that setting renders the script incompatible with existing URLs.
        //All fields with an asterisk must be identical when installing the script on multiple servers if the URL has to be compatible.

        //*This is the key used to encrypt URLs. Add something random here that will not be guessed by others.
        //Changing this will invalidate all existing URLs
        //The key is fed through a hashing algorithm to achieve greater key entropy.
        //Make sure you use a long key of at least 40 characters.
        
define('AB_CRYPT_KEY','**********');

        
//*This is the algorithm to use. If you use an empty string, all ciphers will be listed.
        //We recommend you leave this as 'aes-256-ctr'
        
define('AB_CIPHER','aes-256-ctr');

        
//*This is the initialization vector size for the selected algorithm.
        //16 is correct for 'aes-256-ctr', different algorithms have different IV sizes
        
define('AB_CRYPT_IV_SIZE',16);

        
//*If set to TRUE, no IV will be used in the URL and identical source URLs will look the same
        //This makes the URLs much less secure but shaves off a few bytes.
        //If set to FALSE, AB_CRYPT_IV_SIZE must still have the correct size
        
define('AB_CRYPT_NOIV',FALSE);

        
//*This will use Hexadecimal instead of Base64.
        //The URL is longer but avoids potentially problematic symbols from base64.
        
define('AB_USEHEX',FALSE);

        
//This is the base URL to prepend to the shown links.
        //This must point to your own script, or a script with the same configuration.
        //This is shown to the user in the generated output.
        //if it's not correct the user will get a link that is unusable.
        
define('AB_BASE_URL','https://master.ayra.ch/ab/');

        
//This setting causes the script to send a permanent redirect instead of a temporary redirect.
        //Since the target does not change for a specific URL, you can save bandwidth by setting this to TRUE.
        //If it's TRUE, browsers will remember the redirect and go directly to the target if a link is used a second time.
        
define('AB_REDIR_PERM',FALSE);

        
//This setting defines the key for safebrowsing lookup.
        //Setting to FALSE disables the API.
        //Using SafeBrowsing will increase the load time for links but protects users from harmful websites
        //To get a key, go to https://console.developers.google.com/
        
define('AB_SAFEBROWSING_KEY','**********');

        
//Checks if the URL is reachable via DNS before redirecting.
        //This check is only performed if the URL doesn't points to an IP address.
        //Using this slightly increases the load time for links,
        //but allows us to show a proper message instead of redirecting them to a browser error message.
        
define('AB_CHECK_DNS',TRUE);

        
//Enables API Mode
        //Disabling this will not prevent people from writing tools to make requests manually and parsing the HTML.
        //Enable AB_LIBRARY_ONLY to protect the script or put it into an inaccessible directory.
        
define('AB_ENABLE_API',TRUE);

        
//Allows browsers from other domains to make requests.
        //This will set the Access-Control-Allow-Origin header on valid API requests.
        //Don't enable if your server already sets them.
        //This has no effect if AB_ENABLE_API is not set to TRUE.
        //It's generally better to handle CORS with the server software.
        
define('AB_SEND_CORS',TRUE);
        
        
//Disable HTML Mode
        //If you enable this setting, the script can only be used as php include file.
        //It will return a HTTP 403 if accessed directly.
        //It's better performance wise to put the script into an inaccessible location.
        //The script still reports configuration errors to the output if enabled
        
define('AB_LIBRARY_ONLY',FALSE);

    
//CONDITIONS ==============================

    //The openssl cryptographic functions were added in 5.3
    
if(!function_exists("openssl_random_pseudo_bytes")){
        die(
'This script requires at least PHP 5.3. You are running ' phpversion());
    }
    
//This was added in 5.4 but is not strictly necessary, just nice to have
    
if(!defined('JSON_UNESCAPED_SLASHES')){
        
define('JSON_UNESCAPED_SLASHES',64);
    }
    
//This was added in 5.4 but is not strictly necessary, just nice to have
    
if(!defined('JSON_PRETTY_PRINT')){
        
define('JSON_PRETTY_PRINT',JSON_UNESCAPED_SLASHES<<1);
    }

    
$AB_isIncluded=(get_included_files()[0]!==__FILE__);
    
//Global variables should go here but only if not included
    
if(!$AB_isIncluded){
        
$encrypted_url=FALSE;
    }
    
    
//FUNCTIONS ==============================

    //Converts base64 URL param to real base64
    
function AB_fromparam($x)
    {
        
$x=str_replace('_','+',str_replace('-','/',str_replace('.','=',$x)));
        
//Because strlen(valid_b64) is always a multiple of 4, we can detect the number of '=' to add
        
switch(strlen($x)%4){
            case 
0:
                
//Base64 needs no padding
                
return $x;
            case 
1:
                
//Base64 is one char too long
                //This should never happen.
                //It's much more likely that the string is incomplete but we try anyways
                
return substr($x,0,strlen($x)-1);
            case 
2:
                return 
$x.'==';
            case 
3:
                return 
$x.'=';
        }
    }

    
//Converts problematic base64 chars to make it URL safe
    
function AB_toparam($x)
    {
        
//The '=' at the end is completely optional and we don't need it.
        
return str_replace('+','_',str_replace('/','-',str_replace('=','',$x)));
    }

    
//Encrypts a given binary string
    
function AB_encrypt($content)
    {
        
$iv=AB_CRYPT_NOIV?str_pad('',AB_CRYPT_IV_SIZE,"\0"):random_bytes(AB_CRYPT_IV_SIZE);
        
$key=openssl_digest(AB_CRYPT_KEY,'sha256',TRUE);
        
$crypted=(AB_CRYPT_NOIV?'':$iv).openssl_encrypt($content,AB_CIPHER,$key,OPENSSL_RAW_DATA,$iv);
        if(
AB_USEHEX){
            return 
implode(unpack('H*'$crypted));
        }
        return 
AB_toparam(base64_encode($crypted));
    }

    
//Decrypts the given binary string
    
function AB_decrypt($content)
    {
        if(
AB_USEHEX){
            
$raw=pack('H*',$content);
        }
        else{
            
$raw=base64_decode(AB_fromparam($content));
        }
        if(
$raw===FALSE || strlen($raw)<=AB_CRYPT_IV_SIZE)
        {
            return 
FALSE;
        }
        if(
AB_CRYPT_NOIV){
            
$iv=str_pad('',AB_CRYPT_IV_SIZE,"\0");
            
$url=$raw;
        }
        else{
            
$iv=substr($raw,0,AB_CRYPT_IV_SIZE);
            
$url=substr($raw,AB_CRYPT_IV_SIZE);
        }
        return 
openssl_decrypt($url,AB_CIPHER,openssl_digest(AB_CRYPT_KEY,'sha256',TRUE),OPENSSL_RAW_DATA,$iv);
    }

    
//Checks if the given parameter is an URL
    
function AB_isUrl($x)
    {
        return 
FALSE!==filter_var($x,FILTER_VALIDATE_URL,FILTER_FLAG_SCHEME_REQUIRED|FILTER_FLAG_HOST_REQUIRED) &&
            
//Don't allow some chars. They should be escaped using '%xx' by the user
            
strpbrk($x,"\t\r\n<>")===FALSE;
    }

    
//Extracts the hostname/IP from the URL
    //This function assumes that the URL passed AB_isUrl()
    
function AB_getHostFromUrl($url){
        
$temp=array();
        if(
preg_match('/:\/*([^\/]+)/',$url,$temp)){
            return 
$temp[1];
        }
        return 
null;
    }
    
//Checks if the given name is an IP
    
function AB_isIp($hostname)
    {
        return 
filter_var($hostnameFILTER_VALIDATE_IP) !== FALSE;
    }

    
//Gets the SafeBrowsing Safety rating of an URL
    
function AB_getSafetyRating($url,$matchOnly=FALSE){
        if(
AB_SAFEBROWSING_KEY===FALSE){
            
//Returning an empty array makes the code consider this URL as safe.
            
return $matchOnly?'':array();
        }
        
$json=NULL;
        
//This is the data structure we have to send
        
$data=array(
            
//Our client information
            
'client'=>array(
                
//The reason we use the last 8 characters of the key is to prevent people from just copying the user agent.
                //This way each individual application has a different key
                
'clientId'=>'AB-Redirector/'.substr(AB_SAFEBROWSING_KEY,-8),
                
//Client version. You should change this if you modify anything that could change this function
                
'clientVersion'=>'3.2'
            
),
            
'threatInfo'=>array(
                
//We request all the threats, at least you want MALWARE and SOCIAL_ENGINEERING
                
'threatTypes'=>array('MALWARE','SOCIAL_ENGINEERING','UNWANTED_SOFTWARE','POTENTIALLY_HARMFUL_APPLICATION'),
                
//For any platform
                
'platformTypes'=>array('ANY_PLATFORM'),
                
//We submit an URL
                
'threatEntryTypes'=>array('URL'),
                
//Our URL. You can send multiple by repeating the inner array
                
'threatEntries'=>array(array('url'=>$url))
            )
        );

        
$url='https://safebrowsing.googleapis.com/v4/threatMatches:find?key='.AB_SAFEBROWSING_KEY;
        
$options = array(
            
'http' => array(
                
//The API will send a JSON on HTTP error codes too
                
'ignore_errors' => TRUE,
                
//API demands JSON
                
'header'  => "Content-type: application/json\r\n",
                
//Method is POOST
                
'method'  => 'POST',
                
//The JSON data is sent 'as-is' not as form request
                
'content' => json_encode($data)
            )
        );
        
$ctx=stream_context_create($options);
        
$content=@file_get_contents($url,FALSE,$ctx);
        if(
$content){
            
$json=json_decode($content,TRUE);
        }
        
//Return an array on errors with a NO_REQUEST reason.
        
if(!is_array($json)){
            return 
$matchOnly?'NO_REQUEST':json_decode('{"matches":[{"threatType":"NO_REQUEST"}]}',true);
        }
        if(
$matchOnly){
            if(empty(
$json['matches'][0]['threatType'])){
                return 
'';
            }
            return 
$json['matches'][0]['threatType'];
        }
        return 
$json;
    }

    
//Gets a short HTML classification explanation
    
function AB_getClassification($const){
        switch(
$const){
            
//This is a custom defined code
            
case 'NO_REQUEST':
                return 
'<b>API Unreachable</b>:<br />'.
                    
'We are temporarily unable at this time to determine the status of the provided URL. Until the API works again, the URL is considered unsafe.';
            case 
'POTENTIALLY_HARMFUL_APPLICATION':
                return 
'<b>Potentially Harmful Application</b>:<br />'.
                    
'This website might contain harmful content. It\'s recommended to not download anything.';
            case 
'MALWARE':
                return 
'<b>Malware</b>:<br />'.
                    
'This website is distributing malicious applications. It\'s recommended to not download anything.';
            case 
'UNWANTED_SOFTWARE':
                return 
'<b>Unwanted Software Distribution</b>:<br />'.
                    
'Downloads on this website are likely riddles with unwanted byproducts that could harm your device and/or privacy.';
            case 
'SOCIAL_ENGINEERING':
                return 
'<b>Social Engineering</b>:<br />'.
                    
'This site is designed to trick you into entering sensitive data into forms. Do not attempt to log into any services offered or fill out any forms or answer any questions no matter how real this website looks.';
        }
        
//Unknown error
        
return '<b>'.AB_he($const).'</b>:<br />'.
            
'There is an unspecified danger associated with visiting this site. Be careful.';
    }

    
//Gets a proper rating error message as HTML
    
function AB_getRatingError($url,$const,$redirError){
        
$str='The url <b>'.AB_he($url)."</b> is considered UNSAFE by Google Safe Browsing API.\n\n".
            
'It\'s classified as '.AB_getClassification($const)."\n\n";
            if(
$redirError){
                
$str.="Because of this, this script has decided to not redirect you and you have to visit at your own risk by copying and pasting the URL into your address bar.\n\n".
                    
//Add this text again just to be sure
                    
'In no event shall the provider of this "Link redirector" be liable for any direct, '.
                    
'indirect, incidental, special, exemplary, or consequential damages '.
                    
'(including, but not limited to, procurement of substitute goods or services; '.
                    
'loss of use, data, or profits; or business interruption) however caused and '.
                    
'on any theory of liability, whether in contract, strict liability, or tort '.
                    
'(including negligence or otherwise) arising in any way out of the use of '.
                    
'the shown link, even if advised of the possibility of such damage.';
            }
            else{
                
$str.='Be aware that users will not be able to automatically visit your link and will be shown above warning message instead for as long as the link is considered unsafe. '.
                    
'If you are unhappy with this, you can host your own version and disable the safebrowsing API. '.
                    
'If you believe this is an error, you can visit the '.
                    
'<a target="_blank" rel="noopener noreferer nofollow" href="https://safebrowsing.google.com/safebrowsing/report_error">SafeBrowsing Error Reporter</a>.<br />'.
                    
'There is no need to encrypt a new URL once you fixed the problem because we validate every decryption request against the API.';
            }
        return 
$str;
    }

    
//Shorter HTML Encoder
    
function AB_he($x){
        return 
htmlspecialchars($x);
    }

    
//Validate all constants and returns an error list
    
function AB_checkConstants(){
        
$err=array();
        
//IV Size
        
if(!defined('AB_CRYPT_IV_SIZE') || !is_int(AB_CRYPT_IV_SIZE) || AB_CRYPT_IV_SIZE<|| (AB_CRYPT_IV_SIZE|0)!==AB_CRYPT_IV_SIZE){
            
$err[]='AB_CRYPT_IV_SIZE is not defined or wrong. Please define with the matching size of your algorithm. Use 0 if not needed.';
        }
        
//Hexadecimal URL param
        
if(!defined('AB_USEHEX') || !is_bool(AB_USEHEX)){
            
$err[]='AB_USEHEX is not defined. Define as TRUE or FALSE.';
        }
        
//Library only mode
        
if(!defined('AB_LIBRARY_ONLY') || !is_bool(AB_LIBRARY_ONLY)){
            
$err[]='AB_LIBRARY_ONLY is not defined. Define as TRUE or FALSE.';
        }
        
//Allow usage of this script as an API
        
if(!defined('AB_ENABLE_API') || !is_bool(AB_ENABLE_API)){
            
$err[]='AB_ENABLE_API is not defined. Define as TRUE or FALSE.';
        }
        
//CORS Header
        
if(!defined('AB_SEND_CORS') || !is_bool(AB_SEND_CORS)){
            
$err[]='AB_SEND_CORS is not defined. Define as TRUE or FALSE.';
        }
        
//Permanent redirect option
        
if(!defined('AB_REDIR_PERM') || !is_bool(AB_REDIR_PERM)){
            
$err[]='AB_REDIR_PERM is not defined. Define as TRUE or FALSE.';
        }
        
//DNS checks
        
if(!defined('AB_CHECK_DNS') || !is_bool(AB_CHECK_DNS)){
            
$err[]='AB_CHECK_DNS is not defined. Define as TRUE or FALSE.';
        }
        
//IV Usage
        
if(!defined('AB_CRYPT_NOIV') || !is_bool(AB_CRYPT_NOIV)){
            
$err[]='AB_CRYPT_NOIV is not defined. Define as TRUE or FALSE.';
        }
        
//Base URL
        
if(!defined('AB_BASE_URL') || !is_string(AB_BASE_URL)){
            
$err[]='AB_BASE_URL is not defined. Define as the URL that is prefixed to the crypted parameter. '.
                
'If unsure, the autodetected URL is <b>http'.
                (
$_SERVER['HTTPS']=='on'?'s://':'://').$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].
                
'</b>, but this doesn\'t takes any rewriting into account. '.
                
'If in doubt, just copy the URL from your address bar.';
        }
        
//Safebrowsing key
        
if(!defined('AB_SAFEBROWSING_KEY') || (AB_SAFEBROWSING_KEY!==FALSE && !is_string(AB_SAFEBROWSING_KEY))){
            
$err[]='Please define AB_SAFEBROWSING_KEY properly. Either use an API key or FALSE as value.';
        }
        
//Show help for missing or empty AB_CRYPT_KEY.
        //Don't allow a key made up of entirely the same character either to force people to change a key copied from the source view
        
if(!defined('AB_CRYPT_KEY') || !is_string(AB_CRYPT_KEY) || strlen(AB_CRYPT_KEY)===|| strlen(trim(AB_CRYPT_KEY,AB_CRYPT_KEY[0]))===0)
        {
            
//Generate an example key
            
$exampleKey="";
            while(
strlen($exampleKey)<40){
                
$bytes=openssl_random_pseudo_bytes(40-strlen($exampleKey));
                for(
$i=0;$i<strlen($bytes);$i++){
                    
$code=ord($bytes[$i])%0x80;
                    
//The codes are limited to low ASCII without control characters
                    //By generating a very long key we make up for the lost entropy
                    
if($code>0x20 && $code<0x7F){
                        
$exampleKey.=chr($code);
                    }
                }
            }
            
$err[]='Please define AB_CRYPT_KEY. We highly recommend you use something long (at least 40 chars). Example:<br /><code>'.AB_he($exampleKey).'</code>';
        }
        
//Show help for missing or unsupported AB_CIPHER
        
if(!defined('AB_CIPHER') || !is_string(AB_CIPHER) || !in_array(AB_CIPHER,openssl_get_cipher_methods(FALSE)))
        {
            
$err[]="Please define AB_CIPHER with one of the values below. Not all ciphers are secure. If in doubt, use <code>aes-256-ctr</code> as cipher. List:\n\n".AB_he(implode("\n",openssl_get_cipher_methods(FALSE)));
        }
        return 
$err;
    }

    
//AUTORUN ==============================

    //If not included encrypt/decrypt on its own
    
if(!$AB_isIncluded){
        
$startup_errors=AB_checkConstants();
        if(
AB_LIBRARY_ONLY){
            
header('HTTP/1.1 403 Forbidden',403,TRUE);
            
//We still show the errors to allow for configuration checks
            
if(count($startup_errors)>0){
                echo 
'<ul><li>' implode('</li><li>',$startup_errors) . '</li></ul>';
            }
            else{
                
header('Content-Type: text/plain');
            }
            exit(
'Direct access to this resource has been disabled');
        }

        if(
count($startup_errors)>0){
            
$err=implode("\n",$startup_errors);
        }
        
//Everything OK so far
        
else
        {
            
$err=null;
            
//Show source code but not our keys
            
if(isset($_GET['source']))
            {
                
$repl='**********';
                
$content=highlight_file(__FILE__,TRUE);
                
$content=str_replace(AB_CRYPT_KEY,$repl,$content);
                if(
AB_SAFEBROWSING_KEY!==FALSE){
                    
$content=str_replace(AB_SAFEBROWSING_KEY,$repl,$content);
                }
                echo 
$content;
                exit(
0);
            }

            
$api=AB_ENABLE_API && isset($_POST["api"]);
            
//Encode a new URL if it is present
            
$source=$api?$_POST["api"]:(empty($_POST['encode'])?FALSE:$_POST['encode']);
            if(!empty(
$source))
            {
                
/*
                    This part encrypts the URL.
                    This is done using these steps (assuming all features are enabled):
                    1. AB_isUrl: Check if string is an URL
                    2. AB_encrypt: Encrypt URL
                    3. AB_getSafetyRating: Get Safebrowsing Rating
                    4. Show HTML or API
                    
                    You have to do this manually yourself if you use this as include file
                */
                
if(AB_isUrl($source))
                {
                    
$encrypted_url=AB_encrypt($source);
                    if(
$api){
                        
$ret=array(
                            
'url'=>$_POST['encode'],
                            
'enc'=>$encrypted_url,
                            
'base'=>AB_BASE_URL
                        
);
                        if(
AB_SAFEBROWSING_KEY){
                            
$ret['rating']=AB_getSafetyRating($source,TRUE);
                        }
                        
header("Content-Type: application/json");
                        if(
AB_SEND_CORS){
                            
header("Access-Control-Allow-Origin: *");
                        }
                        echo 
json_encode($ret,JSON_UNESCAPED_SLASHES);
                        exit(
0);
                    }
                    else{
                        if(
AB_SAFEBROWSING_KEY){
                            
$rating=AB_getSafetyRating($source);
                            if(isset(
$rating['matches'][0]['threatType'])){
                                
$err=AB_getRatingError($_POST['encode'],$rating['matches'][0]['threatType'],FALSE);
                            }
                        }
                    }
                }
                else
                {
                    
$err='Please submit a valid URL.';
                }
            }
            
//Decode a URL if it is present
            
elseif(!empty($_GET['url']))
            {
                
/*
                    This part decrypts the URL.
                    This is done using these steps (assuming all features are enabled):
                    1. AB_decrypt: Decrypt the URL
                    2. AB_isUrl: Check if decryption was successful by validating the URL
                    3. AB_getSafetyRating: Get Safebrowsing Rating
                    4. AB_isIp||dns_get_record: Check if URL can be reached by using IP or DNS
                    5. Redirect if step 3 and 4 were successful
                    
                    You have to do this manually yourself if you use this as include file
                */
                
if($value=AB_decrypt($_GET['url']))
                {
                    
//If the decrypted value is not a valid URL, something is wrong with the encrypted payload
                    
if(AB_isUrl($value))
                    {
                        
$rating=AB_getSafetyRating($value);
                        if(empty(
$rating['matches']) || count($rating['matches'])===0){
                            
$hostname=AB_getHostFromUrl($value);
                            if(!
AB_CHECK_DNS || AB_isIp($hostname) || @dns_get_record($hostname,DNS_ANY)){
                                
//Perform any logging or blacklisting here if you want to.
                                //I don't do it because the web server logs all requests anyways by default.
                                
if(AB_REDIR_PERM){
                                    
header('HTTP/1.1 308 Permanent Redirect',TRUE,308);
                                }
                                
header("Location: $value");
                            }
                            else{
                                
$err='Unable to redirect to '.AB_he($value).'. Can\'t resolve '.AB_he($hostname);
                            }
                        }
                        else{
                            
$err=AB_getRatingError($value,$rating['matches'][0]['threatType'],TRUE);
                        }
                    }
                    else
                    {
                        
$err='The Parameter does not decrypt to a valid URL. Common reasons for this are:
    - If you copied the link, you did not copy everything
    - The person who created the link did not copy the entire link
    - The algorithm, IV size or key in this script was changed since the link was created.'
;
                    }
                }
                else
                {
                    
$err='Invalid URL argument. We were unable to parse the argument you gave us.';
                }
            }
        }
    }
    
//Only show HTML if this file was not included
    
if(!$AB_isIncluded){
?>
<!DOCTYPE html>
<?php /*This is a very minimalist HTML file. You might want to edit it to fit your existing design. */ ?>
<html>
    <head>
        <meta http-equiv="content-language" content="en" />
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Antibot link redirector</title>
        <?php
            
/*
                Cheap CSS to look expensive. Do not put this into another file.
                The HTTP request and response headers together will probably be as large as the entire CSS
            */
        
?><style>
            .content{
                font-family:sans-serif;
                max-width:1000px;
                background-color:#DDF;
                border:1px solid #DDF;
                border-radius:20px;
                padding:5px;
                margin:auto;
            }
            .copy{
                text-align:right;
                display:block;
                font-size:8pt;
                color:#666;
            }
            .alert{
                padding:10px;
                margin-bottom:10px;
            }
            .success{
                color:#090;background-color:#DFD;
                border:2px solid #090;
                white-space:nowrap;
                overflow-y:scroll;
            }
            .err{
                color:#900;background-color:#FDD;
                border:2px solid #900;
            }
            #info{display:none;}
            [type=url]{width:100%;}
            p,.spacer{padding-bottom:5px;}
            a,a:visited{color:#00F;font-weight:bold;}
        </style>
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", function () {
                document.querySelector("#help").addEventListener("click", function (e) {
                    document.querySelector('#info').style.display = 'block';
                    document.querySelector("#help").remove();
                    e.preventDefault();
                    e.stopPropagation();
                });
            });
        </script>
        <!-- Always show The Help portion if JavaScript is disabled -->
        <noscript>
            <style>
                #info{display:block !important;}
                #help{display:none;}
            </style>
        </noscript>
    </head>
    <body>
        <div class="content">
            <h1>Link redirector</h1>
            <?php
                
if($err)
                {
                    
//Error occured
                    
echo '<div class="alert err">'.nl2br($err).'</div>';
                }
                if(
$encrypted_url)
                {
                    
//Print encrypted URL in various methods
                    
echo "<div class=\"alert success\"><b>Encrypted links:</b><br />
Raw code:<br /><code>
$encrypted_url</code><br /><br />
Url:<br /><code>"
.AB_BASE_URL."$encrypted_url</code><br /><br />
Markdown:<br /><code>["
.htmlspecialchars($source).']('.AB_BASE_URL."$encrypted_url)</code><br /><br />
Link:<br /><code>"
.htmlspecialchars('<a href="'.AB_BASE_URL."$encrypted_url\">".htmlspecialchars($source).'</a>').'</code></div>';
                }
            
?>
            <form method="post" action="<?php echo AB_BASE_URL?>">
                <div class="spacer">
                    <input type="url" placeholder="Paste URL here" name="encode" value="<?php echo isset($source)?htmlspecialchars($source):""?>" />
                </div>
                <div class="spacer">
                    <input type="submit" value="Encrypt URL" />
                </div>
            </form>
            <a href="#" title="Help" id="help">[Information, License and Disclaimer]</a>
            <?php
            
/*
                The content below is modified depending on the constants you have set.
                If you want to add, modify or remove content, be aware of that to not break the page.
            */
            
?>
            <div id="info">
                <h2>Purpose</h2>
                <p>
                    This site takes a link and scrambles it in a way
                    that makes it impossible to decrypt without visiting this site again.
                    This stops bots from analyzing your links by link text only.
                    To the user this is fully transparent.
                </p>
                <h2>Features</h2>
                <p>
                    This link protector has multiple features that other link protecting scripts lack.
                    <ul>
                        <li><b>Single File only</b>: The entire script is in a single well documented file and has less than 1000 lines of code.</li>
                        <li><b>No Database</b>: The generated Links contain all information to decrypt them. No Database is necessary</li>
                        <li><b>No Write Access</b>: No write access to any portion of the file system is necessary</li>
                        <li><b>Encryption</b>: Links are properly encrypted and not just encoded.</li>
                        <?php if(!AB_CRYPT_NOIV){ ?>
                        <li><b>No link duplicates*</b>: Identical links will look different each time they are encrypted.</li>
                        <?php ?>
                        <li><b>Server connection mandatory</b>: The links can't be decrypted without accessing this service</li>
                        <li><b>Mobile compatible</b>: This redirector works on mobile devices too</li>
                        <?php if(AB_SAFEBROWSING_KEY){ ?>
                        <li><b>SafeBrowsing*</b>: Links are checked against Google Safebrowsing to prevent malicious usage of this service</li>
                        <?php ?>
                        <?php if(AB_ENABLE_API){ ?>
                        <li><b>API*</b>: API allows applications to create links easier</li>
                        <?php ?>
                        <li><b>Distributed Setup</b>: As long as the settings are identical, each file can decrypt links created by another file.</li>
                        <li><b>Library capabilities</b>: This file can be used as individual script and as a library (php include)</li>
                    </ul>
                    Entries marked with <code>*</code> can be turned off and are currently enabled.
                </p>
                <h2>Encryption</h2>
                <p>
                    This is not a simple obfuscation or encoding.
                    This site fully encrypts the link you submit using industry standard AES,
                    which makes it impossible for a bot to know the content without accessing this site.
                    You can set your own key, this makes links encoded on your server unique to yours.
                    Losing or changing the key invalidates all existing URLs.
                </p><?php if(!AB_CRYPT_NOIV){ ?>
                <p>
                    Each link will look different,
                    even if you submit the original link multiple times.
                </p><?php } if(AB_ENABLE_API){ ?>
                <h2>API</h2>
                <p>
                    You can use the API to generate links.
                    Send an URL encoded POST request to <code><?php echo AB_BASE_URL?></code>.
                    with <code>api=Your_Url_Here</code>.
                    You will receive a JSON object with these keys:
                    <ul>
                        <li><b>url</b>: This is your submitted URL</li>
                        <li><b>enc</b>: This is the encrypted Link that has to be appended to 'base'</li>
                        <li><b>base</b>: This is the base URL that the 'enc' data has to be appended to</li><?php if(AB_SAFEBROWSING_KEY){ ?>
                        <li><b>rating</b>: This is the Google Safebrowsing API result. If it's not an empty string, visit 'base'+'enc' to get more details on the problem.</li><?php ?>
                    </ul>
                </p><?php ?>
                <h2>License and Disclaimer</h2>
                <p>
                    This script is open source and licensed under the MIT,
                    you can obtain the source code <a href="<?php echo AB_BASE_URL;?>?source">here</a>.
                </p>
                <p>
                    <?php /*Just to be on the safe side, but you should have server wide terms and conditions somewhere*/ ?>
                    In no event shall the provider of this "Link redirector" be liable for any direct,
                    indirect, incidental, special, exemplary, or consequential damages
                    (including, but not limited to, procurement of substitute goods or services;
                    loss of use, data, or profits; or business interruption) however caused and
                    on any theory of liability, whether in contract, strict liability, or tort
                    (including negligence or otherwise) arising in any way out of the use of
                    this application, even if advised of the possibility of such damage.
                </p><?php if(AB_SAFEBROWSING_KEY){ ?>
                <h2>3rd Party Technologies</h2>
                <p>
                    This site uses Google SafeBrowsing API to determine if a link is safe to visit,
                    this means that every link submitted to this site or visited by users is sent to Google for analysis.<br />
                    This API is in no way a safe way to test link safety and the results should merely be interpreted as a hint.
                    Users should generally be very cautious when an encrypted link leads to an unexpected or unfamiliar site.
                </p><?php ?>
                <p>
                    With your continued usage of this application you consent to the given terms
                </p>
            </div>
            <?php /*If you could leave this here, that would be nice*/
            
?><i class="copy">Copyright &copy; 2017 by /u/AyrA_ch</i>
        </div>
    </body>
</html>
<?php }