├── .gitignore ├── LICENSE ├── README.md └── src ├── .htaccess ├── 404.php ├── 500.php ├── api.php ├── apple-touch-icon.png ├── assets ├── clipboard.min.js ├── icon.png └── style.css ├── composer.json ├── composer.lock ├── composer.phar ├── config.inc.php ├── contribute.json ├── donotlink.sql ├── engine.inc.php ├── favicon.ico ├── index.php ├── link.php ├── redirect.php ├── robots.txt ├── templates ├── .htaccess ├── 404.body.html.php ├── 500.body.html.php ├── faq.body.html.php ├── footer.html.php ├── header.html.php ├── index.body.html.php ├── link.body.html.php └── redirect.html.php └── vendor ├── autoload.php ├── composer ├── ClassLoader.php ├── LICENSE ├── autoload_classmap.php ├── autoload_namespaces.php ├── autoload_psr4.php ├── autoload_real.php ├── autoload_static.php └── installed.json └── hashids └── hashids ├── LICENSE ├── composer.json └── src ├── Hashids.php ├── HashidsException.php ├── HashidsInterface.php └── Math ├── Bc.php ├── Gmp.php └── MathInterface.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Conny Duck 3 | 4 | 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: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DoNotLink 2 | 3 | See donotlink in action at [donotlink.it](https://donotlink.it) 4 | 5 | ## Description 6 | 7 | Donotlink is a simple and fast url shortener that blocks search engines from following links and removes the referer. 8 | Linking to websites via donotlink will not improve the sites position in search engines. 9 | 10 | ## API 11 | send a POST request to https://donotlink.it/api 12 | ``` 13 | POST /api 14 | url=http://example.com 15 | 16 | { 17 | "url": "http:\/\/example.com", 18 | "code": "Y5Yn", 19 | "donotlink": "https:\/\/donotlink.it\/Y5Yn" 20 | } 21 | ``` 22 | 23 | ## Installation - Apache 24 | 25 | Donotlink requires a database (MySQL or MariaDB) and PHP 7. 26 | 27 | ### Apache 28 | 29 | Create a database and set up the redirect table as specified in the **donotlink.sql** file. 30 | Copy the src directory to the root directory of your domain. Edit the **config.inc.php** file accordingly. 31 | You are ready to go. 32 | If you do not use donotlink under the root of your domain, **.htaccess** redirects and **robots.txt** rules will not work anymore. 33 | 34 | ### nginx 35 | 36 | TBD 37 | 38 | ## Libraries 39 | [clipboard.js](https://github.com/zenorocha/clipboard.js) 40 | [hashids.php](https://github.com/ivanakimov/hashids.php) 41 | 42 | ## License 43 | Licensed under the MIT License 44 | 45 | ## Author 46 | Twitter: [@ConnyDuck](https://twitter.com/ConnyDuck) 47 | -------------------------------------------------------------------------------- /src/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | RewriteCond %{REQUEST_FILENAME} !-f 3 | RewriteCond %{REQUEST_FILENAME} !-d 4 | RewriteRule ^l/([a-zA-Z0-9]+)$ link.php?donotlink=$1 [L] 5 | RewriteRule ^([a-zA-Z0-9]+)$ redirect.php?donotlink=$1 [L] 6 | RewriteCond %{REQUEST_URI} ^/(https?://.+)$ 7 | RewriteRule ^(https?:/.+)$ redirect.php?donotlink=%1 [L] 8 | 9 | ErrorDocument 403 /404.php 10 | ErrorDocument 404 /404.php 11 | ErrorDocument 500 /500.php 12 | -------------------------------------------------------------------------------- /src/404.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/500.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/api.php: -------------------------------------------------------------------------------- 1 | "wrong method")); 10 | 11 | } else { 12 | 13 | $engine = new DoNotLinkEngine($_POST['url']); 14 | 15 | $check = $engine->check(); 16 | 17 | if($check !== true) { 18 | http_response_code(400); 19 | echo json_encode(array("error"=>$check)); 20 | return; 21 | } 22 | 23 | $code = $engine->shorten(); 24 | 25 | if($code === NULL) { 26 | http_response_code(500); 27 | echo json_encode(array("error"=>"server error")); 28 | return; 29 | } 30 | 31 | $response = array( 32 | "url"=>$_POST["url"], 33 | "code"=>$code, 34 | "donotlink"=>SERVER_NAME.SERVER_PATH.'/'.$code 35 | ); 36 | 37 | 38 | echo json_encode($response); 39 | 40 | } 41 | 42 | ?> 43 | -------------------------------------------------------------------------------- /src/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connyduck/donotlink/6e33b1b5bacb1e1f9354a779f682ca20df42ad34/src/apple-touch-icon.png -------------------------------------------------------------------------------- /src/assets/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v2.0.1 3 | * https://zenorocha.github.io/clipboard.js 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,o){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=3)}([function(t,e,n){var o,r,i;!function(a,c){r=[t,n(7)],o=c,void 0!==(i="function"==typeof o?o.apply(e,r):o)&&(t.exports=i)}(0,function(t,e){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var o=function(t){return t&&t.__esModule?t:{default:t}}(e),r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.container=t.container,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var t=this,e="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[e?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=(0,o.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=(0,o.default)(this.target),this.copyText()}},{key:"copyText",value:function(){var t=void 0;try{t=document.execCommand(this.action)}catch(e){t=!1}this.handleResult(t)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==(void 0===t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}]),t}();t.exports=a})},function(t,e,n){function o(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!c.string(e))throw new TypeError("Second argument must be a String");if(!c.fn(n))throw new TypeError("Third argument must be a Function");if(c.node(t))return r(t,e,n);if(c.nodeList(t))return i(t,e,n);if(c.string(t))return a(t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function r(t,e,n){return t.addEventListener(e,n),{destroy:function(){t.removeEventListener(e,n)}}}function i(t,e,n){return Array.prototype.forEach.call(t,function(t){t.addEventListener(e,n)}),{destroy:function(){Array.prototype.forEach.call(t,function(t){t.removeEventListener(e,n)})}}}function a(t,e,n){return u(document.body,t,e,n)}var c=n(6),u=n(5);t.exports=o},function(t,e){function n(){}n.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){function o(){r.off(t,o),e.apply(n,arguments)}var r=this;return o._=e,this.on(t,o,n)},emit:function(t){var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;for(o;o0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===d(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=(0,f.default)(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new l.default({action:this.action(e),target:this.target(e),text:this.text(e),container:this.container,trigger:e,emitter:this})}},{key:"defaultAction",value:function(t){return u("action",t)}},{key:"defaultTarget",value:function(t){var e=u("target",t);if(e)return document.querySelector(e)}},{key:"defaultText",value:function(t){return u("text",t)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],e="string"==typeof t?[t]:t,n=!!document.queryCommandSupported;return e.forEach(function(t){n=n&&!!document.queryCommandSupported(t)}),n}}]),e}(s.default);t.exports=p})},function(t,e){function n(t,e){for(;t&&t.nodeType!==o;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}var o=9;if("undefined"!=typeof Element&&!Element.prototype.matches){var r=Element.prototype;r.matches=r.matchesSelector||r.mozMatchesSelector||r.msMatchesSelector||r.oMatchesSelector||r.webkitMatchesSelector}t.exports=n},function(t,e,n){function o(t,e,n,o,r){var a=i.apply(this,arguments);return t.addEventListener(n,a,r),{destroy:function(){t.removeEventListener(n,a,r)}}}function r(t,e,n,r,i){return"function"==typeof t.addEventListener?o.apply(null,arguments):"function"==typeof n?o.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return o(t,e,n,r,i)}))}function i(t,e,n,o){return function(n){n.delegateTarget=a(n.target,e),n.delegateTarget&&o.call(t,n)}}var a=n(4);t.exports=r},function(t,e){e.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},e.nodeList=function(t){var n=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===n||"[object HTMLCollection]"===n)&&"length"in t&&(0===t.length||e.node(t[0]))},e.string=function(t){return"string"==typeof t||t instanceof String},e.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},function(t,e){function n(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var n=t.hasAttribute("readonly");n||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),n||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var o=window.getSelection(),r=document.createRange();r.selectNodeContents(t),o.removeAllRanges(),o.addRange(r),e=o.toString()}return e}t.exports=n}])}); -------------------------------------------------------------------------------- /src/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connyduck/donotlink/6e33b1b5bacb1e1f9354a779f682ca20df42ad34/src/assets/icon.png -------------------------------------------------------------------------------- /src/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | color: #686868; 4 | text-align: center; 5 | line-height: 140%; 6 | padding-top: 1em; 7 | } 8 | 9 | h1 { 10 | font-family: monospace; 11 | font-weight: 100; 12 | font-size: 260%; 13 | margin-bottom: 1em; 14 | } 15 | 16 | h1 span { 17 | color: #0078e7; 18 | } 19 | 20 | form { 21 | margin: 0 auto; 22 | position: relative; 23 | } 24 | 25 | input, button { 26 | margin: 1em; 27 | } 28 | 29 | input#url { 30 | margin-top: 0; 31 | font-size: medium; 32 | border: 1px solid #ccc; 33 | box-shadow: inset 0 1px 3px #ddd; 34 | border-radius: 4px; 35 | vertical-align: middle; 36 | padding: .5em .6em; 37 | min-width: 16em; 38 | max-width: 42em; 39 | width: 80%; 40 | } 41 | 42 | input#url:focus { 43 | outline: 0; 44 | border-color: #0078e7; 45 | } 46 | 47 | button#submitBtn { 48 | font-size: medium; 49 | cursor: pointer; 50 | padding: .6em 1.6em; 51 | border: none; 52 | background-color: #0078e7; 53 | color: #fff; 54 | text-decoration: none; 55 | border-radius: 3px; 56 | outline: 0; 57 | } 58 | 59 | form button#submitBtn:disabled { 60 | background-color: #97c8f7; 61 | background-image: none; 62 | cursor: not-allowed; 63 | box-shadow: none; 64 | } 65 | 66 | button#submitBtn:hover, 67 | button#submitBtn:focus { 68 | background-color: #0069d3; 69 | background-image: linear-gradient(#0075ea, #0066cc); 70 | } 71 | 72 | button#submitBtn:active { 73 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, 0 0 6px rgba(0, 0, 0, 0.20) inset; 74 | } 75 | 76 | div { 77 | padding: 0 1em; 78 | min-width: 16em; 79 | margin: 1em auto 1em; 80 | max-width: 44em; 81 | } 82 | 83 | @media (min-width: 32em) { 84 | div { 85 | width: 80%; 86 | } 87 | } 88 | 89 | div.faq { 90 | text-align: left; 91 | margin: 2.5em auto 1em; 92 | } 93 | 94 | h2 { 95 | font-weight: normal; 96 | font-size: 150%; 97 | margin-bottom: .5em; 98 | } 99 | 100 | p, ul { 101 | margin-top: 0em; 102 | } 103 | 104 | ul li { 105 | list-style-type: circle; 106 | margin-left: 0; 107 | margin-bottom: .3em; 108 | } 109 | 110 | a { 111 | transition: color .2s ease-in-out; 112 | color: #686868; 113 | } 114 | 115 | a:hover, a:focus, a:active { 116 | color: #0078e7; 117 | } 118 | 119 | p.credit { 120 | text-align: center; 121 | margin-top: 2em; 122 | } 123 | 124 | p.github, p.patreon { 125 | text-align: center; 126 | margin: 1em; 127 | } 128 | 129 | .loadingButton { 130 | position: relative; 131 | margin: 0 auto; 132 | } 133 | 134 | .loader { 135 | position: absolute; 136 | top: calc( 50% - 13px); 137 | left: calc( 50% - 12px); 138 | border: 4px solid transparent; 139 | border-top: 4px solid #fff; 140 | border-radius: 50%; 141 | width: 20px; 142 | height: 20px; 143 | padding: 0px; 144 | min-width: 0px; 145 | margin: 0 auto; 146 | animation: spin 1s linear infinite; 147 | cursor: not-allowed; 148 | } 149 | 150 | @keyframes spin { 151 | 0% { 152 | transform: rotate(0deg); 153 | } 154 | 100% { 155 | transform: rotate(360deg); 156 | } 157 | } 158 | 159 | .tooltipped { 160 | position: relative; 161 | } 162 | 163 | .tooltipped::after { 164 | position: absolute; 165 | z-index: 1000000; 166 | display: none; 167 | padding: .4em 1em; 168 | font-size: small; 169 | color: #fff; 170 | text-align: center; 171 | pointer-events: none; 172 | content: attr(tooltiptext); 173 | background: #686868; 174 | border-radius: 4px; 175 | opacity: 0; 176 | left: 50%; 177 | transform: translate(-50%, 0); 178 | bottom: 100%; 179 | margin-bottom: 10px; 180 | } 181 | 182 | .tooltipped::before { 183 | position: absolute; 184 | z-index: 1000001; 185 | display: none; 186 | width: 0; 187 | height: 0; 188 | pointer-events: none; 189 | content: ""; 190 | border: 6px solid transparent; 191 | opacity: 0; 192 | top: -10px; 193 | left: 50%; 194 | transform: translate(-50%, 0); 195 | bottom: auto; 196 | border-top-color: #686868; 197 | } 198 | 199 | @keyframes tooltip-appear { 200 | from { 201 | opacity: 0; 202 | } 203 | to { 204 | opacity: 1; 205 | } 206 | } 207 | 208 | .tooltipped:hover::before, 209 | .tooltipped:active::before, 210 | .tooltipped:focus::before, 211 | .tooltipped:hover::after, 212 | .tooltipped:active::after, 213 | .tooltipped:focus::after { 214 | display: inline-block; 215 | animation: tooltip-appear .25s ease-in forwards; 216 | } 217 | 218 | @media (prefers-color-scheme: dark) { 219 | body { 220 | color: #fff; 221 | background-color: #343434; 222 | } 223 | 224 | h1 span { 225 | color: #5CA6EB; 226 | } 227 | 228 | input#url { 229 | background-color: #424242; 230 | border: 1px solid #666; 231 | box-shadow: inset 0 1px 3px #343434; 232 | color: #fff; 233 | } 234 | 235 | input#url:focus { 236 | border-color: #5CA6EB; 237 | } 238 | 239 | a { 240 | color: #fff; 241 | } 242 | 243 | a:hover, a:focus, a:active { 244 | color: #5CA6EB; 245 | } 246 | 247 | button#submitBtn { 248 | background-color: #5CA6EB; 249 | color: #343434; 250 | } 251 | 252 | form button#submitBtn:disabled { 253 | background-color: #486D90; 254 | } 255 | 256 | button#submitBtn:hover, 257 | button#submitBtn:focus { 258 | background-color: #86baeb; 259 | background-image: linear-gradient(#8dbeeb, #84b9eb); 260 | } 261 | 262 | .loader { 263 | border-top: 4px solid #343434; 264 | } 265 | 266 | } -------------------------------------------------------------------------------- /src/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "hashids/hashids": "^3.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "3900fb7200d3cbdb2321a5548213bc23", 8 | "packages": [ 9 | { 10 | "name": "hashids/hashids", 11 | "version": "3.0.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/ivanakimov/hashids.php.git", 15 | "reference": "b6c61142bfe36d43740a5419d11c351dddac0458" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/ivanakimov/hashids.php/zipball/b6c61142bfe36d43740a5419d11c351dddac0458", 20 | "reference": "b6c61142bfe36d43740a5419d11c351dddac0458", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": "^7.1.3" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": "^7.0" 28 | }, 29 | "suggest": { 30 | "ext-bcmath": "Required to use BC Math arbitrary precision mathematics (*).", 31 | "ext-gmp": "Required to use GNU multiple precision mathematics (*)." 32 | }, 33 | "type": "library", 34 | "extra": { 35 | "branch-alias": { 36 | "dev-master": "3.0-dev" 37 | } 38 | }, 39 | "autoload": { 40 | "psr-4": { 41 | "Hashids\\": "src/" 42 | } 43 | }, 44 | "notification-url": "https://packagist.org/downloads/", 45 | "license": [ 46 | "MIT" 47 | ], 48 | "authors": [ 49 | { 50 | "name": "Ivan Akimov", 51 | "email": "ivan@barreleye.com", 52 | "homepage": "https://twitter.com/IvanAkimov" 53 | }, 54 | { 55 | "name": "Vincent Klaiber", 56 | "email": "hello@vinkla.com", 57 | "homepage": "https://vinkla.com" 58 | } 59 | ], 60 | "description": "Generate short, unique, non-sequential ids (like YouTube and Bitly) from numbers", 61 | "homepage": "http://hashids.org/php", 62 | "keywords": [ 63 | "bitly", 64 | "decode", 65 | "encode", 66 | "hash", 67 | "hashid", 68 | "hashids", 69 | "ids", 70 | "obfuscate", 71 | "youtube" 72 | ], 73 | "time": "2018-03-12T16:30:09+00:00" 74 | } 75 | ], 76 | "packages-dev": [], 77 | "aliases": [], 78 | "minimum-stability": "stable", 79 | "stability-flags": [], 80 | "prefer-stable": false, 81 | "prefer-lowest": false, 82 | "platform": [], 83 | "platform-dev": [] 84 | } 85 | -------------------------------------------------------------------------------- /src/composer.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connyduck/donotlink/6e33b1b5bacb1e1f9354a779f682ca20df42ad34/src/composer.phar -------------------------------------------------------------------------------- /src/config.inc.php: -------------------------------------------------------------------------------- 1 | 29 | -------------------------------------------------------------------------------- /src/contribute.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "donotlink", 3 | "description": "A simple and fast url shortener that blocks search engines from following links and removes the referer.", 4 | "repository": { 5 | "url": "https://github.com/connyduck/donotlink", 6 | "license": "MIT" 7 | }, 8 | "participate": { 9 | "docs": "https://github.com/connyduck/donotlink" 10 | }, 11 | "bugs": { 12 | "report": "https://github.com/connyduck/donotlink/issues" 13 | }, 14 | "urls": { 15 | "prod": "https://donotlink.it" 16 | }, 17 | "keywords": [ 18 | "php", 19 | "css", 20 | "html5", 21 | "javascript" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /src/donotlink.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `redirect` ( 2 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 3 | `url` varchar(1000) NOT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /src/engine.inc.php: -------------------------------------------------------------------------------- 1 | url = trim($url); 15 | } 16 | 17 | //returns true or a string containing the error message 18 | function check() { 19 | if(!isset($this->url)) { 20 | return "missing input"; 21 | } 22 | if (strlen($this->url) > 1000) { 23 | return "url too long"; 24 | } 25 | if (!preg_match(URL_REGEX, $this->url)) { 26 | return "malformed url"; 27 | } 28 | if(strpos($this->url, SERVER_NAME) === 0) { 29 | return "cannot shorten ".SITE_NAME." links"; 30 | } 31 | 32 | $this->checked = true; 33 | 34 | return true; 35 | } 36 | 37 | //returns null in case of error, or the code of the shortened link 38 | function shorten() { 39 | 40 | if($this->checked == false) { 41 | return NULL; 42 | } 43 | 44 | // Create connection 45 | $conn = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME); 46 | 47 | // Check connection 48 | if (!$conn) { 49 | return NULL; 50 | } 51 | 52 | if($sql = mysqli_prepare($conn, "INSERT INTO redirect (url) VALUES (?)")) { 53 | 54 | mysqli_stmt_bind_param($sql, "s", $this->url); 55 | 56 | mysqli_stmt_execute($sql); 57 | 58 | mysqli_stmt_close($sql); 59 | } else { 60 | return NULL; 61 | } 62 | 63 | $last_id = mysqli_insert_id($conn); 64 | 65 | $hashids = new Hashids(CODE_SALT, MIN_CODE_LENGTH); 66 | 67 | return $hashids->encode($last_id); 68 | } 69 | } 70 | 71 | ?> 72 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connyduck/donotlink/6e33b1b5bacb1e1f9354a779f682ca20df42ad34/src/favicon.ico -------------------------------------------------------------------------------- /src/index.php: -------------------------------------------------------------------------------- 1 | check(); 18 | 19 | if($check !== true) { 20 | http_response_code(400); 21 | include 'templates/header.html.php'; 22 | echo $check; 23 | include 'templates/footer.html.php'; 24 | return; 25 | } 26 | 27 | $code = $engine->shorten(); 28 | 29 | if($code === NULL) { 30 | http_response_code(500); 31 | include 'templates/header.html.php'; 32 | include 'templates/500.body.html.php'; 33 | include 'templates/footer.html.php'; 34 | return; 35 | } 36 | 37 | http_response_code(303); 38 | header('Location: '.SERVER_NAME.SERVER_PATH.'/l/'.$code); 39 | } 40 | 41 | ?> 42 | -------------------------------------------------------------------------------- /src/link.php: -------------------------------------------------------------------------------- 1 | decode($code); 55 | 56 | if(count($id) != 1) { 57 | http_response_code(404); 58 | include 'templates/header.html.php'; 59 | include 'templates/404.body.html.php'; 60 | include 'templates/footer.html.php'; 61 | return; 62 | } 63 | 64 | if($sql = mysqli_prepare($conn, "SELECT url FROM redirect WHERE id = ?")) { 65 | 66 | mysqli_stmt_bind_param($sql, "i", $id[0]); 67 | 68 | mysqli_stmt_execute($sql); 69 | 70 | mysqli_stmt_bind_result($sql, $url); 71 | 72 | mysqli_stmt_fetch($sql); 73 | 74 | mysqli_stmt_close($sql); 75 | 76 | } else { 77 | http_response_code(500); 78 | include 'templates/header.html.php'; 79 | include 'templates/500.body.html.php'; 80 | include 'templates/footer.html.php'; 81 | return; 82 | } 83 | 84 | if($url == null) { 85 | http_response_code(404); 86 | include 'templates/header.html.php'; 87 | include 'templates/404.body.html.php'; 88 | include 'templates/footer.html.php'; 89 | return; 90 | } 91 | 92 | $donotlink_url = SERVER_NAME.SERVER_PATH.'/'.$code; 93 | 94 | include 'templates/header.html.php'; 95 | include 'templates/link.body.html.php'; 96 | include 'templates/faq.body.html.php'; 97 | include 'templates/footer.html.php'; 98 | 99 | ?> 100 | -------------------------------------------------------------------------------- /src/redirect.php: -------------------------------------------------------------------------------- 1 | decode($code); 56 | 57 | if(count($id) != 1) { 58 | http_response_code(404); 59 | include 'templates/header.html.php'; 60 | include 'templates/404.body.html.php'; 61 | include 'templates/footer.html.php'; 62 | return; 63 | } 64 | 65 | // Create connection 66 | $conn = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME); 67 | 68 | // Check connection 69 | if (!$conn) { 70 | http_response_code(500); 71 | include 'templates/header.html.php'; 72 | include 'templates/500.body.html.php'; 73 | include 'templates/footer.html.php'; 74 | return; 75 | } 76 | 77 | if($sql = mysqli_prepare($conn, "SELECT url FROM redirect WHERE id = ?")) { 78 | 79 | mysqli_stmt_bind_param($sql, "i", $id[0]); 80 | 81 | mysqli_stmt_execute($sql); 82 | 83 | mysqli_stmt_bind_result($sql, $url); 84 | 85 | mysqli_stmt_fetch($sql); 86 | 87 | mysqli_stmt_close($sql); 88 | 89 | } else { 90 | http_response_code(500); 91 | include 'templates/header.html.php'; 92 | include 'templates/500.body.html.php'; 93 | include 'templates/footer.html.php'; 94 | return; 95 | } 96 | 97 | if($url == null) { 98 | http_response_code(404); 99 | include 'templates/header.html.php'; 100 | include 'templates/404.body.html.php'; 101 | include 'templates/footer.html.php'; 102 | return; 103 | } 104 | 105 | if (!preg_match(URL_REGEX, $url)) { 106 | http_response_code(500); 107 | include 'templates/header.html.php'; 108 | include 'templates/500.body.html.php'; 109 | include 'templates/footer.html.php'; 110 | return; 111 | } 112 | 113 | include 'templates/redirect.html.php'; 114 | 115 | ?> 116 | -------------------------------------------------------------------------------- /src/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Allow: /$ 3 | Allow: /assets/ 4 | Disallow: / 5 | -------------------------------------------------------------------------------- /src/templates/.htaccess: -------------------------------------------------------------------------------- 1 | deny from all 2 | -------------------------------------------------------------------------------- /src/templates/404.body.html.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Something's wrong here...

4 | 5 |

Uh oh, couldn't find a link for the URL you clicked.
6 | Most URLs are 4-6 characters, only include letters and numbers (and are case sensitive) (e.g. /zxwL) or have another URL appended (e.g. /http://example.com).
7 |

8 | 9 |
10 | -------------------------------------------------------------------------------- /src/templates/500.body.html.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Something's wrong here...

4 | 5 |

Uh oh, has encountered an internal error.

6 | 7 |
8 | -------------------------------------------------------------------------------- /src/templates/faq.body.html.php: -------------------------------------------------------------------------------- 1 |
2 |

3 | Whenever you link a website, its position in search engines is strengthened. Sometimes you want to post a link to a website without improving its rank. This is where comes in. 4 |

5 |

What does do?

6 |

7 | Using instead of linking to questionable websites directly will prevent your links from improving these websites' position in search engines. Additionally will remove the referer, so the linked website will not know where its visitors are coming from. 8 |

9 | 10 |

How does it work?

11 |
    12 |
  • This url is blocked in our robots.txt file, so (search engine) robots are discouraged from crawling it.
  • 13 |
  • The "nofollow" attribute of the link and the intermediate page give robots another reminder to not crawl the link.
  • 14 |
  • If a known robot does decide to crawl the link, our code will identify it and serve it a blank page (403 Forbidden) instead of redirecting to the url.
  • 15 |
  • Redirects are implemented via JavaScript and not via http response status codes so the browser will remove the referer from the request.
  • 16 |
17 | 18 |

19 | To use either copy and paste the link in the form above or prepend / like this /http://example.com. A link always needs to start with http:// or https://. 20 |

21 | 22 |

What does not do?

23 |
    24 |
  • does not use cookies or any other technology to track its users.
  • 25 |
  • does not scan the linked site for malware.
  • 26 |
  • does not prevent the linked site from getting ad revenue from visitors.
  • 27 |
28 |

created by @ConnyDuck

29 |

30 | Support on Patreon 31 | 32 |

33 |

Get the source code on Github

34 |
35 | -------------------------------------------------------------------------------- /src/templates/footer.html.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/templates/header.html.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <?php echo SITE_NAME; ?> 8 | 9 | 12 | 13 | "; 14 | ?> 15 | 16 | 17 | 18 | 19 | 20 | 21 |

doNOTlink.it

22 | -------------------------------------------------------------------------------- /src/templates/index.body.html.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
8 | 24 | -------------------------------------------------------------------------------- /src/templates/link.body.html.php: -------------------------------------------------------------------------------- 1 |
Your link to is ready!
2 |
3 |
4 | 5 |
6 | 7 | 21 | Create another link 22 | -------------------------------------------------------------------------------- /src/templates/redirect.html.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | <?php echo SITE_NAME; ?> 4 | 5 | "/> 6 | 9 | 10 | Redirecting to "> 11 | -------------------------------------------------------------------------------- /src/vendor/autoload.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Autoload; 14 | 15 | /** 16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. 17 | * 18 | * $loader = new \Composer\Autoload\ClassLoader(); 19 | * 20 | * // register classes with namespaces 21 | * $loader->add('Symfony\Component', __DIR__.'/component'); 22 | * $loader->add('Symfony', __DIR__.'/framework'); 23 | * 24 | * // activate the autoloader 25 | * $loader->register(); 26 | * 27 | * // to enable searching the include path (eg. for PEAR packages) 28 | * $loader->setUseIncludePath(true); 29 | * 30 | * In this example, if you try to use a class in the Symfony\Component 31 | * namespace or one of its children (Symfony\Component\Console for instance), 32 | * the autoloader will first look for the class under the component/ 33 | * directory, and it will then fallback to the framework/ directory if not 34 | * found before giving up. 35 | * 36 | * This class is loosely based on the Symfony UniversalClassLoader. 37 | * 38 | * @author Fabien Potencier 39 | * @author Jordi Boggiano 40 | * @see http://www.php-fig.org/psr/psr-0/ 41 | * @see http://www.php-fig.org/psr/psr-4/ 42 | */ 43 | class ClassLoader 44 | { 45 | // PSR-4 46 | private $prefixLengthsPsr4 = array(); 47 | private $prefixDirsPsr4 = array(); 48 | private $fallbackDirsPsr4 = array(); 49 | 50 | // PSR-0 51 | private $prefixesPsr0 = array(); 52 | private $fallbackDirsPsr0 = array(); 53 | 54 | private $useIncludePath = false; 55 | private $classMap = array(); 56 | private $classMapAuthoritative = false; 57 | private $missingClasses = array(); 58 | private $apcuPrefix; 59 | 60 | public function getPrefixes() 61 | { 62 | if (!empty($this->prefixesPsr0)) { 63 | return call_user_func_array('array_merge', $this->prefixesPsr0); 64 | } 65 | 66 | return array(); 67 | } 68 | 69 | public function getPrefixesPsr4() 70 | { 71 | return $this->prefixDirsPsr4; 72 | } 73 | 74 | public function getFallbackDirs() 75 | { 76 | return $this->fallbackDirsPsr0; 77 | } 78 | 79 | public function getFallbackDirsPsr4() 80 | { 81 | return $this->fallbackDirsPsr4; 82 | } 83 | 84 | public function getClassMap() 85 | { 86 | return $this->classMap; 87 | } 88 | 89 | /** 90 | * @param array $classMap Class to filename map 91 | */ 92 | public function addClassMap(array $classMap) 93 | { 94 | if ($this->classMap) { 95 | $this->classMap = array_merge($this->classMap, $classMap); 96 | } else { 97 | $this->classMap = $classMap; 98 | } 99 | } 100 | 101 | /** 102 | * Registers a set of PSR-0 directories for a given prefix, either 103 | * appending or prepending to the ones previously set for this prefix. 104 | * 105 | * @param string $prefix The prefix 106 | * @param array|string $paths The PSR-0 root directories 107 | * @param bool $prepend Whether to prepend the directories 108 | */ 109 | public function add($prefix, $paths, $prepend = false) 110 | { 111 | if (!$prefix) { 112 | if ($prepend) { 113 | $this->fallbackDirsPsr0 = array_merge( 114 | (array) $paths, 115 | $this->fallbackDirsPsr0 116 | ); 117 | } else { 118 | $this->fallbackDirsPsr0 = array_merge( 119 | $this->fallbackDirsPsr0, 120 | (array) $paths 121 | ); 122 | } 123 | 124 | return; 125 | } 126 | 127 | $first = $prefix[0]; 128 | if (!isset($this->prefixesPsr0[$first][$prefix])) { 129 | $this->prefixesPsr0[$first][$prefix] = (array) $paths; 130 | 131 | return; 132 | } 133 | if ($prepend) { 134 | $this->prefixesPsr0[$first][$prefix] = array_merge( 135 | (array) $paths, 136 | $this->prefixesPsr0[$first][$prefix] 137 | ); 138 | } else { 139 | $this->prefixesPsr0[$first][$prefix] = array_merge( 140 | $this->prefixesPsr0[$first][$prefix], 141 | (array) $paths 142 | ); 143 | } 144 | } 145 | 146 | /** 147 | * Registers a set of PSR-4 directories for a given namespace, either 148 | * appending or prepending to the ones previously set for this namespace. 149 | * 150 | * @param string $prefix The prefix/namespace, with trailing '\\' 151 | * @param array|string $paths The PSR-4 base directories 152 | * @param bool $prepend Whether to prepend the directories 153 | * 154 | * @throws \InvalidArgumentException 155 | */ 156 | public function addPsr4($prefix, $paths, $prepend = false) 157 | { 158 | if (!$prefix) { 159 | // Register directories for the root namespace. 160 | if ($prepend) { 161 | $this->fallbackDirsPsr4 = array_merge( 162 | (array) $paths, 163 | $this->fallbackDirsPsr4 164 | ); 165 | } else { 166 | $this->fallbackDirsPsr4 = array_merge( 167 | $this->fallbackDirsPsr4, 168 | (array) $paths 169 | ); 170 | } 171 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { 172 | // Register directories for a new namespace. 173 | $length = strlen($prefix); 174 | if ('\\' !== $prefix[$length - 1]) { 175 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 176 | } 177 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 178 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 179 | } elseif ($prepend) { 180 | // Prepend directories for an already registered namespace. 181 | $this->prefixDirsPsr4[$prefix] = array_merge( 182 | (array) $paths, 183 | $this->prefixDirsPsr4[$prefix] 184 | ); 185 | } else { 186 | // Append directories for an already registered namespace. 187 | $this->prefixDirsPsr4[$prefix] = array_merge( 188 | $this->prefixDirsPsr4[$prefix], 189 | (array) $paths 190 | ); 191 | } 192 | } 193 | 194 | /** 195 | * Registers a set of PSR-0 directories for a given prefix, 196 | * replacing any others previously set for this prefix. 197 | * 198 | * @param string $prefix The prefix 199 | * @param array|string $paths The PSR-0 base directories 200 | */ 201 | public function set($prefix, $paths) 202 | { 203 | if (!$prefix) { 204 | $this->fallbackDirsPsr0 = (array) $paths; 205 | } else { 206 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; 207 | } 208 | } 209 | 210 | /** 211 | * Registers a set of PSR-4 directories for a given namespace, 212 | * replacing any others previously set for this namespace. 213 | * 214 | * @param string $prefix The prefix/namespace, with trailing '\\' 215 | * @param array|string $paths The PSR-4 base directories 216 | * 217 | * @throws \InvalidArgumentException 218 | */ 219 | public function setPsr4($prefix, $paths) 220 | { 221 | if (!$prefix) { 222 | $this->fallbackDirsPsr4 = (array) $paths; 223 | } else { 224 | $length = strlen($prefix); 225 | if ('\\' !== $prefix[$length - 1]) { 226 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 227 | } 228 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 229 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 230 | } 231 | } 232 | 233 | /** 234 | * Turns on searching the include path for class files. 235 | * 236 | * @param bool $useIncludePath 237 | */ 238 | public function setUseIncludePath($useIncludePath) 239 | { 240 | $this->useIncludePath = $useIncludePath; 241 | } 242 | 243 | /** 244 | * Can be used to check if the autoloader uses the include path to check 245 | * for classes. 246 | * 247 | * @return bool 248 | */ 249 | public function getUseIncludePath() 250 | { 251 | return $this->useIncludePath; 252 | } 253 | 254 | /** 255 | * Turns off searching the prefix and fallback directories for classes 256 | * that have not been registered with the class map. 257 | * 258 | * @param bool $classMapAuthoritative 259 | */ 260 | public function setClassMapAuthoritative($classMapAuthoritative) 261 | { 262 | $this->classMapAuthoritative = $classMapAuthoritative; 263 | } 264 | 265 | /** 266 | * Should class lookup fail if not found in the current class map? 267 | * 268 | * @return bool 269 | */ 270 | public function isClassMapAuthoritative() 271 | { 272 | return $this->classMapAuthoritative; 273 | } 274 | 275 | /** 276 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled. 277 | * 278 | * @param string|null $apcuPrefix 279 | */ 280 | public function setApcuPrefix($apcuPrefix) 281 | { 282 | $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; 283 | } 284 | 285 | /** 286 | * The APCu prefix in use, or null if APCu caching is not enabled. 287 | * 288 | * @return string|null 289 | */ 290 | public function getApcuPrefix() 291 | { 292 | return $this->apcuPrefix; 293 | } 294 | 295 | /** 296 | * Registers this instance as an autoloader. 297 | * 298 | * @param bool $prepend Whether to prepend the autoloader or not 299 | */ 300 | public function register($prepend = false) 301 | { 302 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); 303 | } 304 | 305 | /** 306 | * Unregisters this instance as an autoloader. 307 | */ 308 | public function unregister() 309 | { 310 | spl_autoload_unregister(array($this, 'loadClass')); 311 | } 312 | 313 | /** 314 | * Loads the given class or interface. 315 | * 316 | * @param string $class The name of the class 317 | * @return bool|null True if loaded, null otherwise 318 | */ 319 | public function loadClass($class) 320 | { 321 | if ($file = $this->findFile($class)) { 322 | includeFile($file); 323 | 324 | return true; 325 | } 326 | } 327 | 328 | /** 329 | * Finds the path to the file where the class is defined. 330 | * 331 | * @param string $class The name of the class 332 | * 333 | * @return string|false The path if found, false otherwise 334 | */ 335 | public function findFile($class) 336 | { 337 | // class map lookup 338 | if (isset($this->classMap[$class])) { 339 | return $this->classMap[$class]; 340 | } 341 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { 342 | return false; 343 | } 344 | if (null !== $this->apcuPrefix) { 345 | $file = apcu_fetch($this->apcuPrefix.$class, $hit); 346 | if ($hit) { 347 | return $file; 348 | } 349 | } 350 | 351 | $file = $this->findFileWithExtension($class, '.php'); 352 | 353 | // Search for Hack files if we are running on HHVM 354 | if (false === $file && defined('HHVM_VERSION')) { 355 | $file = $this->findFileWithExtension($class, '.hh'); 356 | } 357 | 358 | if (null !== $this->apcuPrefix) { 359 | apcu_add($this->apcuPrefix.$class, $file); 360 | } 361 | 362 | if (false === $file) { 363 | // Remember that this class does not exist. 364 | $this->missingClasses[$class] = true; 365 | } 366 | 367 | return $file; 368 | } 369 | 370 | private function findFileWithExtension($class, $ext) 371 | { 372 | // PSR-4 lookup 373 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; 374 | 375 | $first = $class[0]; 376 | if (isset($this->prefixLengthsPsr4[$first])) { 377 | $subPath = $class; 378 | while (false !== $lastPos = strrpos($subPath, '\\')) { 379 | $subPath = substr($subPath, 0, $lastPos); 380 | $search = $subPath.'\\'; 381 | if (isset($this->prefixDirsPsr4[$search])) { 382 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); 383 | foreach ($this->prefixDirsPsr4[$search] as $dir) { 384 | if (file_exists($file = $dir . $pathEnd)) { 385 | return $file; 386 | } 387 | } 388 | } 389 | } 390 | } 391 | 392 | // PSR-4 fallback dirs 393 | foreach ($this->fallbackDirsPsr4 as $dir) { 394 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 395 | return $file; 396 | } 397 | } 398 | 399 | // PSR-0 lookup 400 | if (false !== $pos = strrpos($class, '\\')) { 401 | // namespaced class name 402 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 403 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); 404 | } else { 405 | // PEAR-like class name 406 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; 407 | } 408 | 409 | if (isset($this->prefixesPsr0[$first])) { 410 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { 411 | if (0 === strpos($class, $prefix)) { 412 | foreach ($dirs as $dir) { 413 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 414 | return $file; 415 | } 416 | } 417 | } 418 | } 419 | } 420 | 421 | // PSR-0 fallback dirs 422 | foreach ($this->fallbackDirsPsr0 as $dir) { 423 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 424 | return $file; 425 | } 426 | } 427 | 428 | // PSR-0 include paths. 429 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 430 | return $file; 431 | } 432 | 433 | return false; 434 | } 435 | } 436 | 437 | /** 438 | * Scope isolated include. 439 | * 440 | * Prevents access to $this/self from included files. 441 | */ 442 | function includeFile($file) 443 | { 444 | include $file; 445 | } 446 | -------------------------------------------------------------------------------- /src/vendor/composer/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) Nils Adermann, Jordi Boggiano 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished 9 | to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /src/vendor/composer/autoload_classmap.php: -------------------------------------------------------------------------------- 1 | array($vendorDir . '/hashids/hashids/src'), 10 | ); 11 | -------------------------------------------------------------------------------- /src/vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); 27 | if ($useStaticLoader) { 28 | require_once __DIR__ . '/autoload_static.php'; 29 | 30 | call_user_func(\Composer\Autoload\ComposerStaticInitc08d5bfd5b6d7ffc218a831191c09ca9::getInitializer($loader)); 31 | } else { 32 | $map = require __DIR__ . '/autoload_namespaces.php'; 33 | foreach ($map as $namespace => $path) { 34 | $loader->set($namespace, $path); 35 | } 36 | 37 | $map = require __DIR__ . '/autoload_psr4.php'; 38 | foreach ($map as $namespace => $path) { 39 | $loader->setPsr4($namespace, $path); 40 | } 41 | 42 | $classMap = require __DIR__ . '/autoload_classmap.php'; 43 | if ($classMap) { 44 | $loader->addClassMap($classMap); 45 | } 46 | } 47 | 48 | $loader->register(true); 49 | 50 | return $loader; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | 11 | array ( 12 | 'Hashids\\' => 8, 13 | ), 14 | ); 15 | 16 | public static $prefixDirsPsr4 = array ( 17 | 'Hashids\\' => 18 | array ( 19 | 0 => __DIR__ . '/..' . '/hashids/hashids/src', 20 | ), 21 | ); 22 | 23 | public static function getInitializer(ClassLoader $loader) 24 | { 25 | return \Closure::bind(function () use ($loader) { 26 | $loader->prefixLengthsPsr4 = ComposerStaticInitc08d5bfd5b6d7ffc218a831191c09ca9::$prefixLengthsPsr4; 27 | $loader->prefixDirsPsr4 = ComposerStaticInitc08d5bfd5b6d7ffc218a831191c09ca9::$prefixDirsPsr4; 28 | 29 | }, null, ClassLoader::class); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "hashids/hashids", 4 | "version": "3.0.0", 5 | "version_normalized": "3.0.0.0", 6 | "source": { 7 | "type": "git", 8 | "url": "https://github.com/ivanakimov/hashids.php.git", 9 | "reference": "b6c61142bfe36d43740a5419d11c351dddac0458" 10 | }, 11 | "dist": { 12 | "type": "zip", 13 | "url": "https://api.github.com/repos/ivanakimov/hashids.php/zipball/b6c61142bfe36d43740a5419d11c351dddac0458", 14 | "reference": "b6c61142bfe36d43740a5419d11c351dddac0458", 15 | "shasum": "" 16 | }, 17 | "require": { 18 | "php": "^7.1.3" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "^7.0" 22 | }, 23 | "suggest": { 24 | "ext-bcmath": "Required to use BC Math arbitrary precision mathematics (*).", 25 | "ext-gmp": "Required to use GNU multiple precision mathematics (*)." 26 | }, 27 | "time": "2018-03-12T16:30:09+00:00", 28 | "type": "library", 29 | "extra": { 30 | "branch-alias": { 31 | "dev-master": "3.0-dev" 32 | } 33 | }, 34 | "installation-source": "dist", 35 | "autoload": { 36 | "psr-4": { 37 | "Hashids\\": "src/" 38 | } 39 | }, 40 | "notification-url": "https://packagist.org/downloads/", 41 | "license": [ 42 | "MIT" 43 | ], 44 | "authors": [ 45 | { 46 | "name": "Ivan Akimov", 47 | "email": "ivan@barreleye.com", 48 | "homepage": "https://twitter.com/IvanAkimov" 49 | }, 50 | { 51 | "name": "Vincent Klaiber", 52 | "email": "hello@vinkla.com", 53 | "homepage": "https://vinkla.com" 54 | } 55 | ], 56 | "description": "Generate short, unique, non-sequential ids (like YouTube and Bitly) from numbers", 57 | "homepage": "http://hashids.org/php", 58 | "keywords": [ 59 | "bitly", 60 | "decode", 61 | "encode", 62 | "hash", 63 | "hashid", 64 | "hashids", 65 | "ids", 66 | "obfuscate", 67 | "youtube" 68 | ] 69 | } 70 | ] 71 | -------------------------------------------------------------------------------- /src/vendor/hashids/hashids/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2018 Ivan Akimov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/vendor/hashids/hashids/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hashids/hashids", 3 | "description": "Generate short, unique, non-sequential ids (like YouTube and Bitly) from numbers", 4 | "keywords": ["hashids", "hashid", "hash", "ids", "youtube", "bitly", "encode", "decode", "obfuscate"], 5 | "homepage": "http://hashids.org/php", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Ivan Akimov", 10 | "email": "ivan@barreleye.com", 11 | "homepage": "https://twitter.com/IvanAkimov" 12 | }, 13 | { 14 | "name": "Vincent Klaiber", 15 | "email": "hello@vinkla.com", 16 | "homepage": "https://vinkla.com" 17 | } 18 | ], 19 | "require": { 20 | "php": "^7.1.3" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "^7.0" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Hashids\\": "src/" 28 | } 29 | }, 30 | "autoload-dev": { 31 | "psr-4": { 32 | "Hashids\\Tests\\": "tests/" 33 | } 34 | }, 35 | "config": { 36 | "preferred-install": "dist" 37 | }, 38 | "extra": { 39 | "branch-alias": { 40 | "dev-master": "3.0-dev" 41 | } 42 | }, 43 | "suggest": { 44 | "ext-bcmath": "Required to use BC Math arbitrary precision mathematics (*).", 45 | "ext-gmp": "Required to use GNU multiple precision mathematics (*)." 46 | }, 47 | "minimum-stability": "dev", 48 | "prefer-stable": true 49 | } 50 | -------------------------------------------------------------------------------- /src/vendor/hashids/hashids/src/Hashids.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Hashids; 13 | 14 | use Hashids\Math\Bc; 15 | use Hashids\Math\Gmp; 16 | use RuntimeException; 17 | 18 | /** 19 | * This is the hashids class. 20 | * 21 | * @author Ivan Akimov 22 | * @author Vincent Klaiber 23 | * @author Johnson Page 24 | */ 25 | class Hashids implements HashidsInterface 26 | { 27 | /** 28 | * The seps divider. 29 | * 30 | * @var float 31 | */ 32 | const SEP_DIV = 3.5; 33 | 34 | /** 35 | * The guard divider. 36 | * 37 | * @var float 38 | */ 39 | const GUARD_DIV = 12; 40 | 41 | /** 42 | * The alphabet string. 43 | * 44 | * @var string 45 | */ 46 | protected $alphabet; 47 | 48 | /** 49 | * Shuffled alphabets, referenced by alphabet and salt. 50 | * 51 | * @var array 52 | */ 53 | protected $shuffledAlphabets; 54 | 55 | /** 56 | * The seps string. 57 | * 58 | * @var string 59 | */ 60 | protected $seps = 'cfhistuCFHISTU'; 61 | 62 | /** 63 | * The guards string. 64 | * 65 | * @var string 66 | */ 67 | protected $guards; 68 | 69 | /** 70 | * The minimum hash length. 71 | * 72 | * @var int 73 | */ 74 | protected $minHashLength; 75 | 76 | /** 77 | * The salt string. 78 | * 79 | * @var string 80 | */ 81 | protected $salt; 82 | 83 | /** 84 | * The math class. 85 | * 86 | * @var \Hashids\Math\MathInterface 87 | */ 88 | protected $math; 89 | 90 | /** 91 | * Create a new hashids instance. 92 | * 93 | * @param string $salt 94 | * @param int $minHashLength 95 | * @param string $alphabet 96 | * 97 | * @throws \Hashids\HashidsException 98 | * 99 | * @return void 100 | */ 101 | public function __construct($salt = '', $minHashLength = 0, $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890') 102 | { 103 | $this->salt = $salt; 104 | $this->minHashLength = $minHashLength; 105 | $this->alphabet = implode('', array_unique(str_split($alphabet))); 106 | $this->math = $this->getMathExtension(); 107 | 108 | if (strlen($this->alphabet) < 16) { 109 | throw new HashidsException('Alphabet must contain at least 16 unique characters.'); 110 | } 111 | 112 | if (strpos($this->alphabet, ' ') !== false) { 113 | throw new HashidsException('Alphabet can\'t contain spaces.'); 114 | } 115 | 116 | $alphabetArray = str_split($this->alphabet); 117 | $sepsArray = str_split($this->seps); 118 | 119 | $this->seps = implode('', array_intersect($sepsArray, $alphabetArray)); 120 | $this->alphabet = implode('', array_diff($alphabetArray, $sepsArray)); 121 | $this->seps = $this->shuffle($this->seps, $this->salt); 122 | 123 | if (!$this->seps || (strlen($this->alphabet) / strlen($this->seps)) > self::SEP_DIV) { 124 | $sepsLength = (int) ceil(strlen($this->alphabet) / self::SEP_DIV); 125 | 126 | if ($sepsLength > strlen($this->seps)) { 127 | $diff = $sepsLength - strlen($this->seps); 128 | $this->seps .= substr($this->alphabet, 0, $diff); 129 | $this->alphabet = substr($this->alphabet, $diff); 130 | } 131 | } 132 | 133 | $this->alphabet = $this->shuffle($this->alphabet, $this->salt); 134 | $guardCount = (int) ceil(strlen($this->alphabet) / self::GUARD_DIV); 135 | 136 | if (strlen($this->alphabet) < 3) { 137 | $this->guards = substr($this->seps, 0, $guardCount); 138 | $this->seps = substr($this->seps, $guardCount); 139 | } else { 140 | $this->guards = substr($this->alphabet, 0, $guardCount); 141 | $this->alphabet = substr($this->alphabet, $guardCount); 142 | } 143 | } 144 | 145 | /** 146 | * Encode parameters to generate a hash. 147 | * 148 | * @param mixed $numbers 149 | * 150 | * @return string 151 | */ 152 | public function encode(...$numbers) 153 | { 154 | $ret = ''; 155 | 156 | if (1 === count($numbers) && is_array($numbers[0])) { 157 | $numbers = $numbers[0]; 158 | } 159 | 160 | if (!$numbers) { 161 | return $ret; 162 | } 163 | 164 | foreach ($numbers as $number) { 165 | $isNumber = ctype_digit((string) $number); 166 | 167 | if (!$isNumber) { 168 | return $ret; 169 | } 170 | } 171 | 172 | $alphabet = $this->alphabet; 173 | $numbersSize = count($numbers); 174 | $numbersHashInt = 0; 175 | 176 | foreach ($numbers as $i => $number) { 177 | $numbersHashInt += $this->math->intval($this->math->mod($number, ($i + 100))); 178 | } 179 | 180 | $lottery = $ret = $alphabet[$numbersHashInt % strlen($alphabet)]; 181 | foreach ($numbers as $i => $number) { 182 | $alphabet = $this->shuffle($alphabet, substr($lottery.$this->salt.$alphabet, 0, strlen($alphabet))); 183 | $ret .= $last = $this->hash($number, $alphabet); 184 | 185 | if ($i + 1 < $numbersSize) { 186 | $number %= (ord($last) + $i); 187 | $sepsIndex = $this->math->intval($this->math->mod($number, strlen($this->seps))); 188 | $ret .= $this->seps[$sepsIndex]; 189 | } 190 | } 191 | 192 | if (strlen($ret) < $this->minHashLength) { 193 | $guardIndex = ($numbersHashInt + ord($ret[0])) % strlen($this->guards); 194 | 195 | $guard = $this->guards[$guardIndex]; 196 | $ret = $guard.$ret; 197 | 198 | if (strlen($ret) < $this->minHashLength) { 199 | $guardIndex = ($numbersHashInt + ord($ret[2])) % strlen($this->guards); 200 | $guard = $this->guards[$guardIndex]; 201 | 202 | $ret .= $guard; 203 | } 204 | } 205 | 206 | $halfLength = (int) (strlen($alphabet) / 2); 207 | while (strlen($ret) < $this->minHashLength) { 208 | $alphabet = $this->shuffle($alphabet, $alphabet); 209 | $ret = substr($alphabet, $halfLength).$ret.substr($alphabet, 0, $halfLength); 210 | 211 | $excess = strlen($ret) - $this->minHashLength; 212 | if ($excess > 0) { 213 | $ret = substr($ret, $excess / 2, $this->minHashLength); 214 | } 215 | } 216 | 217 | return $ret; 218 | } 219 | 220 | /** 221 | * Decode a hash to the original parameter values. 222 | * 223 | * @param string $hash 224 | * 225 | * @return array 226 | */ 227 | public function decode($hash) 228 | { 229 | $ret = []; 230 | 231 | if (!is_string($hash) || !($hash = trim($hash))) { 232 | return $ret; 233 | } 234 | 235 | $alphabet = $this->alphabet; 236 | 237 | $ret = []; 238 | 239 | $hashBreakdown = str_replace(str_split($this->guards), ' ', $hash); 240 | $hashArray = explode(' ', $hashBreakdown); 241 | 242 | $i = count($hashArray) == 3 || count($hashArray) == 2 ? 1 : 0; 243 | 244 | $hashBreakdown = $hashArray[$i]; 245 | 246 | if (isset($hashBreakdown[0])) { 247 | $lottery = $hashBreakdown[0]; 248 | $hashBreakdown = substr($hashBreakdown, 1); 249 | 250 | $hashBreakdown = str_replace(str_split($this->seps), ' ', $hashBreakdown); 251 | $hashArray = explode(' ', $hashBreakdown); 252 | 253 | foreach ($hashArray as $subHash) { 254 | $alphabet = $this->shuffle($alphabet, substr($lottery.$this->salt.$alphabet, 0, strlen($alphabet))); 255 | $result = $this->unhash($subHash, $alphabet); 256 | if ($this->math->greaterThan($result, PHP_INT_MAX)) { 257 | $ret[] = $this->math->strval($result); 258 | } else { 259 | $ret[] = $this->math->intval($result); 260 | } 261 | } 262 | 263 | if ($this->encode($ret) != $hash) { 264 | $ret = []; 265 | } 266 | } 267 | 268 | return $ret; 269 | } 270 | 271 | /** 272 | * Encode hexadecimal values and generate a hash string. 273 | * 274 | * @param string $str 275 | * 276 | * @return string 277 | */ 278 | public function encodeHex($str) 279 | { 280 | if (!ctype_xdigit((string) $str)) { 281 | return ''; 282 | } 283 | 284 | $numbers = trim(chunk_split($str, 12, ' ')); 285 | $numbers = explode(' ', $numbers); 286 | 287 | foreach ($numbers as $i => $number) { 288 | $numbers[$i] = hexdec('1'.$number); 289 | } 290 | 291 | return call_user_func_array([$this, 'encode'], $numbers); 292 | } 293 | 294 | /** 295 | * Decode a hexadecimal hash. 296 | * 297 | * @param string $hash 298 | * 299 | * @return string 300 | */ 301 | public function decodeHex($hash) 302 | { 303 | $ret = ''; 304 | $numbers = $this->decode($hash); 305 | 306 | foreach ($numbers as $i => $number) { 307 | $ret .= substr(dechex($number), 1); 308 | } 309 | 310 | return $ret; 311 | } 312 | 313 | /** 314 | * Shuffle alphabet by given salt. 315 | * 316 | * @param string $alphabet 317 | * @param string $salt 318 | * 319 | * @return string 320 | */ 321 | protected function shuffle($alphabet, $salt) 322 | { 323 | $key = $alphabet.' '.$salt; 324 | 325 | if (isset($this->shuffledAlphabets[$key])) { 326 | return $this->shuffledAlphabets[$key]; 327 | } 328 | 329 | $saltLength = strlen($salt); 330 | 331 | if (!$saltLength) { 332 | return $alphabet; 333 | } 334 | 335 | for ($i = strlen($alphabet) - 1, $v = 0, $p = 0; $i > 0; $i--, $v++) { 336 | $v %= $saltLength; 337 | $p += $int = ord($salt[$v]); 338 | $j = ($int + $v + $p) % $i; 339 | 340 | $temp = $alphabet[$j]; 341 | $alphabet[$j] = $alphabet[$i]; 342 | $alphabet[$i] = $temp; 343 | } 344 | 345 | $this->shuffledAlphabets[$key] = $alphabet; 346 | 347 | return $alphabet; 348 | } 349 | 350 | /** 351 | * Hash given input value. 352 | * 353 | * @param string $input 354 | * @param string $alphabet 355 | * 356 | * @return string 357 | */ 358 | protected function hash($input, $alphabet) 359 | { 360 | $hash = ''; 361 | $alphabetLength = strlen($alphabet); 362 | 363 | do { 364 | $hash = $alphabet[$this->math->intval($this->math->mod($input, $alphabetLength))].$hash; 365 | 366 | $input = $this->math->divide($input, $alphabetLength); 367 | } while ($this->math->greaterThan($input, 0)); 368 | 369 | return $hash; 370 | } 371 | 372 | /** 373 | * Unhash given input value. 374 | * 375 | * @param string $input 376 | * @param string $alphabet 377 | * 378 | * @return int 379 | */ 380 | protected function unhash($input, $alphabet) 381 | { 382 | $number = 0; 383 | $inputLength = strlen($input); 384 | 385 | if ($inputLength && $alphabet) { 386 | $alphabetLength = strlen($alphabet); 387 | $inputChars = str_split($input); 388 | 389 | foreach ($inputChars as $char) { 390 | $position = strpos($alphabet, $char); 391 | $number = $this->math->multiply($number, $alphabetLength); 392 | $number = $this->math->add($number, $position); 393 | } 394 | } 395 | 396 | return $number; 397 | } 398 | 399 | /** 400 | * Get BC Math or GMP extension. 401 | * 402 | * @codeCoverageIgnore 403 | * 404 | * @throws \RuntimeException 405 | * 406 | * @return \Hashids\Math\Bc|\Hashids\Math\Gmp 407 | */ 408 | protected function getMathExtension() 409 | { 410 | if (extension_loaded('gmp')) { 411 | return new Gmp(); 412 | } 413 | 414 | if (extension_loaded('bcmath')) { 415 | return new Bc(); 416 | } 417 | 418 | throw new RuntimeException('Missing BC Math or GMP extension.'); 419 | } 420 | } 421 | -------------------------------------------------------------------------------- /src/vendor/hashids/hashids/src/HashidsException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Hashids; 13 | 14 | use InvalidArgumentException; 15 | 16 | /** 17 | * This is the hashids exception class. 18 | * 19 | * @author Vincent Klaiber 20 | */ 21 | class HashidsException extends InvalidArgumentException 22 | { 23 | // 24 | } 25 | -------------------------------------------------------------------------------- /src/vendor/hashids/hashids/src/HashidsInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Hashids; 13 | 14 | /** 15 | * This is the hashids interface. 16 | * 17 | * @author Ivan Akimov 18 | * @author Vincent Klaiber 19 | */ 20 | interface HashidsInterface 21 | { 22 | /** 23 | * Encode parameters to generate a hash. 24 | * 25 | * @param mixed $numbers 26 | * 27 | * @return string 28 | */ 29 | public function encode(...$numbers); 30 | 31 | /** 32 | * Decode a hash to the original parameter values. 33 | * 34 | * @param string $hash 35 | * 36 | * @return array 37 | */ 38 | public function decode($hash); 39 | 40 | /** 41 | * Encode hexadecimal values and generate a hash string. 42 | * 43 | * @param string $str 44 | * 45 | * @return string 46 | */ 47 | public function encodeHex($str); 48 | 49 | /** 50 | * Decode a hexadecimal hash. 51 | * 52 | * @param string $hash 53 | * 54 | * @return string 55 | */ 56 | public function decodeHex($hash); 57 | } 58 | -------------------------------------------------------------------------------- /src/vendor/hashids/hashids/src/Math/Bc.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Hashids\Math; 13 | 14 | /** 15 | * This is the Bc math class. 16 | * 17 | * @author Vincent Klaiber 18 | * @author Jakub Kramarz 19 | * @author Johnson Page 20 | */ 21 | class Bc implements MathInterface 22 | { 23 | /** 24 | * Add two arbitrary-length integers. 25 | * 26 | * @param string $a 27 | * @param string $b 28 | * 29 | * @return string 30 | */ 31 | public function add($a, $b) 32 | { 33 | return bcadd($a, $b, 0); 34 | } 35 | 36 | /** 37 | * Multiply two arbitrary-length integers. 38 | * 39 | * @param string $a 40 | * @param string $b 41 | * 42 | * @return string 43 | */ 44 | public function multiply($a, $b) 45 | { 46 | return bcmul($a, $b, 0); 47 | } 48 | 49 | /** 50 | * Divide two arbitrary-length integers. 51 | * 52 | * @param string $a 53 | * @param string $b 54 | * 55 | * @return string 56 | */ 57 | public function divide($a, $b) 58 | { 59 | return bcdiv($a, $b, 0); 60 | } 61 | 62 | /** 63 | * Compute arbitrary-length integer modulo. 64 | * 65 | * @param string $n 66 | * @param string $d 67 | * 68 | * @return string 69 | */ 70 | public function mod($n, $d) 71 | { 72 | return bcmod($n, $d); 73 | } 74 | 75 | /** 76 | * Compares two arbitrary-length integers. 77 | * 78 | * @param string $a 79 | * @param string $b 80 | * 81 | * @return bool 82 | */ 83 | public function greaterThan($a, $b) 84 | { 85 | return bccomp($a, $b, 0) > 0; 86 | } 87 | 88 | /** 89 | * Converts arbitrary-length integer to PHP integer. 90 | * 91 | * @param string $a 92 | * 93 | * @return int 94 | */ 95 | public function intval($a) 96 | { 97 | return intval($a); 98 | } 99 | 100 | /** 101 | * Converts arbitrary-length integer to PHP string. 102 | * 103 | * @param string $a 104 | * 105 | * @return string 106 | */ 107 | public function strval($a) 108 | { 109 | return $a; 110 | } 111 | 112 | /** 113 | * Converts PHP integer to arbitrary-length integer. 114 | * 115 | * @param int $a 116 | * 117 | * @return string 118 | */ 119 | public function get($a) 120 | { 121 | return $a; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/vendor/hashids/hashids/src/Math/Gmp.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Hashids\Math; 13 | 14 | /** 15 | * This is the Gmp math class. 16 | * 17 | * @author Vincent Klaiber 18 | * @author Jakub Kramarz 19 | * @author Johnson Page 20 | */ 21 | class Gmp implements MathInterface 22 | { 23 | /** 24 | * Add two arbitrary-length integers. 25 | * 26 | * @param string $a 27 | * @param string $b 28 | * 29 | * @return string 30 | */ 31 | public function add($a, $b) 32 | { 33 | return gmp_add($a, $b); 34 | } 35 | 36 | /** 37 | * Multiply two arbitrary-length integers. 38 | * 39 | * @param string $a 40 | * @param string $b 41 | * 42 | * @return string 43 | */ 44 | public function multiply($a, $b) 45 | { 46 | return gmp_mul($a, $b); 47 | } 48 | 49 | /** 50 | * Divide two arbitrary-length integers. 51 | * 52 | * @param string $a 53 | * @param string $b 54 | * 55 | * @return string 56 | */ 57 | public function divide($a, $b) 58 | { 59 | return gmp_div_q($a, $b); 60 | } 61 | 62 | /** 63 | * Compute arbitrary-length integer modulo. 64 | * 65 | * @param string $n 66 | * @param string $d 67 | * 68 | * @return string 69 | */ 70 | public function mod($n, $d) 71 | { 72 | return gmp_mod($n, $d); 73 | } 74 | 75 | /** 76 | * Compares two arbitrary-length integers. 77 | * 78 | * @param string $a 79 | * @param string $b 80 | * 81 | * @return bool 82 | */ 83 | public function greaterThan($a, $b) 84 | { 85 | return gmp_cmp($a, $b) > 0; 86 | } 87 | 88 | /** 89 | * Converts arbitrary-length integer to PHP integer. 90 | * 91 | * @param string $a 92 | * 93 | * @return int 94 | */ 95 | public function intval($a) 96 | { 97 | return gmp_intval($a); 98 | } 99 | 100 | /** 101 | * Converts arbitrary-length integer to PHP string. 102 | * 103 | * @param string $a 104 | * 105 | * @return string 106 | */ 107 | public function strval($a) 108 | { 109 | return gmp_strval($a); 110 | } 111 | 112 | /** 113 | * Converts PHP integer to arbitrary-length integer. 114 | * 115 | * @param int $a 116 | * 117 | * @return string 118 | */ 119 | public function get($a) 120 | { 121 | return gmp_init($a); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/vendor/hashids/hashids/src/Math/MathInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Hashids\Math; 13 | 14 | /** 15 | * Interface for different math extensions. 16 | * 17 | * @author Vincent Klaiber 18 | * @author Jakub Kramarz 19 | * @author Johnson Page 20 | */ 21 | interface MathInterface 22 | { 23 | /** 24 | * Add two arbitrary-length integers. 25 | * 26 | * @param string $a 27 | * @param string $b 28 | * 29 | * @return string 30 | */ 31 | public function add($a, $b); 32 | 33 | /** 34 | * Multiply two arbitrary-length integers. 35 | * 36 | * @param string $a 37 | * @param string $b 38 | * 39 | * @return string 40 | */ 41 | public function multiply($a, $b); 42 | 43 | /** 44 | * Divide two arbitrary-length integers. 45 | * 46 | * @param string $a 47 | * @param string $b 48 | * 49 | * @return string 50 | */ 51 | public function divide($a, $b); 52 | 53 | /** 54 | * Compute arbitrary-length integer modulo. 55 | * 56 | * @param string $n 57 | * @param string $d 58 | * 59 | * @return string 60 | */ 61 | public function mod($n, $d); 62 | 63 | /** 64 | * Compares two arbitrary-length integers. 65 | * 66 | * @param string $a 67 | * @param string $b 68 | * 69 | * @return bool 70 | */ 71 | public function greaterThan($a, $b); 72 | 73 | /** 74 | * Converts arbitrary-length integer to PHP integer. 75 | * 76 | * @param string $a 77 | * 78 | * @return int 79 | */ 80 | public function intval($a); 81 | 82 | /** 83 | * Converts arbitrary-length integer to PHP string. 84 | * 85 | * @param string $a 86 | * 87 | * @return string 88 | */ 89 | public function strval($a); 90 | 91 | /** 92 | * Converts PHP integer to arbitrary-length integer. 93 | * 94 | * @param int $a 95 | * 96 | * @return string 97 | */ 98 | public function get($a); 99 | } 100 | --------------------------------------------------------------------------------