{"id":6803,"date":"2017-07-10T13:25:15","date_gmt":"2017-07-10T11:25:15","guid":{"rendered":"https:\/\/anexia.com\/stagingblog\/?p=6803"},"modified":"2022-04-21T14:23:28","modified_gmt":"2022-04-21T12:23:28","slug":"setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter","status":"publish","type":"post","link":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/","title":{"rendered":"Setting up your custom URL shortener (incl. statistics) with CodeIgniter"},"content":{"rendered":"<p>There are now numerous short URL services (also known as <em>URL shorteners)<\/em> on the Internet \u2013 but what exactly do they do, and why do we actually need them? As the name suggests, these services provide a short URL for any web address. What this means is that you can submit any web address to the service provider and they will give you back a shortened version of it.<br \/>\nThis is particularly useful in allowing you to send friends or relatives a short link instead of an extremely long one. Many social media outlets also limit the number of characters per message, and these short URL services enjoy an important role here too as a way of getting around certain limits. The most commonly used short URL service in the world at present is the US-run <a href=\"https:\/\/bitly.com\/\">Bit.ly<\/a>.<\/p>\n<p>Below I will show you how easily you can build a service like this for yourself using the CodeIgniter framework:<\/p>\n<div class=\"row wp-gallery-row\"><div class=\"col-md-4 col-sm-4 text-center\"><a href='https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/07\/ci-urlshortener_1-1024x518.png' ><img src='https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/07\/ci-urlshortener_1-170x170.png' \/><\/a><\/div><div class=\"col-md-4 col-sm-4 text-center\"><a href='https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/07\/ci-urlshortener_2-1024x518.png' ><img src='https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/07\/ci-urlshortener_2-170x170.png' \/><\/a><\/div><\/div>\n<h2>HOW DOES A SHORT URL SERVICE WORK IN PRACTICE?<\/h2>\n<p>Virtually all short URL providers have services roughly based on the same principle:<\/p>\n<p>On the provider\u2019s home page there is usually a text field where you can enter your original URL, from which a unique short URL is then generated. Anyone who attempts to visit this short URL is then instantly redirected to the respective destination address \u2013 i.e. the address which was entered when generating the URL. In addition to this, many providers also supply statistics about access etc.<\/p>\n<h2>CODEIGNITER SETUP<\/h2>\n<p>In the following section, I will show you how the CodeIgniter setup works.<br \/>\n<a href=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/codeigniter_logo.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-504\" src=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/codeigniter_logo-300x70.png\" alt=\"CodeIgniter Logo\" width=\"300\" height=\"70\" srcset=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/codeigniter_logo-300x70.png 300w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/codeigniter_logo-600x140.png 600w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/codeigniter_logo-1024x239.png 1024w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<h3>Prepare the framework<\/h3>\n<p>In order to get started with our short URL service, we first need a foundation on which we can build.<br \/>\nTo do so, download the latest version of the framework from the <a href=\"https:\/\/www.codeigniter.com\/\">CodeIgniter homepage<\/a>. This is currently version 3.1.5.<\/p>\n<p>Next, copy all the files, ideally to the subfolder \u201cci-urlshortener\u201d on the web server (e.g. XAMPP, LAMP, etc.), and open its root directory in your browser, e.g. http:\/\/localhost\/ci-urlshortener\/.<\/p>\n<p>Once all of the requirements for the framework are met, you should then see the CodeIgniter welcome page.<\/p>\n<p>To ensure that the speaking URLs can also be accessed correctly, create a <strong>.htaccess<\/strong> file with the following content:<\/p>\n<pre class=\"lang:default decode:true\">RewriteEngine on\r\n\r\nRewriteRule ^(assets)($|\/) - [L]\r\nRewriteRule .* index.php<\/pre>\n<p>If necessary, an optional environment variable can be specified here to distinguish between a development system (\u201c<em>development<\/em>\u201d), test system (\u201c<em>testing<\/em>\u201d) or production system (\u201c<em>production<\/em>\u201d).<br \/>\nThis would look as follows:<\/p>\n<pre class=\"lang:default decode:true \">SetEnv CI_ENV development<\/pre>\n<p>&nbsp;<\/p>\n<p>Next, open <strong>\/application\/config\/autoload.php<\/strong> (the autoloader configuration file) and add the URL and form helper along with the database library. We will need these components later.<\/p>\n<pre class=\"lang:php decode:true\">$autoload['libraries'] = array('database');\r\n$autoload['helper'] = array('url', 'form');<\/pre>\n<p>&nbsp;<\/p>\n<p>In <strong>\/application\/config\/routes.php<\/strong> (the route configuration file), we now need to change the default controller from \u201c<em>welcome<\/em>\u201d to \u201c<em>home<\/em>\u201d since we want our URL shortener application to be loaded by default later.<\/p>\n<p>We will also define two additional routes here: one for redirects (as a catch-all) and one for statistics.<\/p>\n<pre class=\"lang:php decode:true\">$route['default_controller'] = 'home';\r\n$route['404_override'] = '';\r\n$route['translate_uri_dashes'] = FALSE;\r\n\r\n$route['(:any)\/stats'] = 'home\/stats\/$1';\r\n$route['(:any)'] = 'home\/redirect\/$1';<\/pre>\n<p>The redirect route (catch-all) is deliberately defined last, otherwise it would intercept all other routes and so routing would not work properly.<\/p>\n<h3>CREATE INDEX PAGE AND STORE URLS<\/h3>\n<p>Having referred to a \u201chome\u201d controller in the route configuration, we also need to create one. To do so, navigate to <strong>\/application\/controller <\/strong>and create a file named <strong>Home.php<\/strong> (case-sensitive!).<br \/>\nIn this file we now need to create the basic framework of 3 actions: one for the index page, one for the redirect itself, and one for the statistics.<\/p>\n<pre class=\"lang:php decode:true \">&lt;?php\r\ndefined('BASEPATH') OR exit('No direct script access allowed');\r\n\r\nclass Home extends CI_Controller {\r\n\r\n\r\n\tpublic function __construct()\r\n\t{\r\n\t\tparent::__construct();\r\n\t}\r\n\t\r\n\t\r\n\tpublic function index()\r\n\t{\r\n\t\t\r\n\t}\r\n\t\r\n\t\r\n\tpublic function redirect( $alias )\r\n\t{\r\n\t\t\r\n\t}\r\n\t\r\n\t\r\n\tpublic function stats( $alias )\r\n\t{\r\n\t\t\r\n\t}\r\n}\r\n<\/pre>\n<p>Later on, we will load our models in the constructor above to avoid having to do this separately for every single action.<\/p>\n<p>Now we have our controller defined along with the necessary actions.Next we create our database tables as follows:<\/p>\n<pre class=\"lang:mysql decode:true \">CREATE TABLE `urls` ( \r\n\t`id` INT NOT NULL AUTO_INCREMENT , \r\n\t`url` VARCHAR(255) NOT NULL , \r\n\t`alias` VARCHAR(100) NOT NULL , \r\n\t`created` DATETIME NOT NULL , \r\n\tPRIMARY KEY (`id`), \r\n\tINDEX (`alias`)\r\n) ENGINE = InnoDB;\r\n\r\n\r\nCREATE TABLE `statistics` ( \r\n\t`id` INT NOT NULL AUTO_INCREMENT , \r\n\t`url_id` INT NOT NULL , \r\n\t`created` DATETIME NOT NULL , \r\n\tPRIMARY KEY (`id`), \r\n\tINDEX (`url_id`)\r\n) ENGINE = InnoDB;<\/pre>\n<p>This gives us one table for redirects (storing URLs with associated aliases) and one for statistics (logging each time a particular URL is accessed).<\/p>\n<p>Next we will create a model for the URL table. To do so, navigate to <strong>\/application\/models<\/strong> and create a new file named<strong> Url_model.php<\/strong>.<\/p>\n<p>We need the following functions here: the ability to add a new URL (with <strong>add_url()<\/strong>) and to retrieve a URL by ID (with <strong>get_url_by_id()<\/strong>) or alias (with <strong>get_url()<\/strong>).<\/p>\n<pre class=\"lang:php decode:true\">&lt;?php\r\ndefined('BASEPATH') OR exit('No direct script access allowed');\r\n\r\nclass Url_model extends CI_Model {\r\n\t\r\n\t\r\n\tfunction add_url( $url )\r\n\t{\r\n\t\t\/\/ build up data array\r\n\t\t$data = array(\r\n\t\t\t'url'\t\t=&gt; (string) $url,\r\n\t\t\t'alias'\t\t=&gt; (string) uniqid(), \/\/ creates a random key\r\n\t\t\t'created'\t=&gt; date('Y-m-d H:i:s'),\r\n\t\t);\r\n\t\t \r\n\t\t\/\/ inserts the data into database\r\n\t\t$this-&gt;db-&gt;insert('urls', $data);\r\n\t\t\r\n\t\t\/\/ return this ID of the new inserted record\r\n\t\treturn $this-&gt;db-&gt;insert_id();\r\n\t}\r\n\t\r\n\t\r\n\tpublic function get_url_by_id( $id )\r\n\t{\r\n\t\t$this-&gt;db-&gt;select('*');\r\n\t\t$this-&gt;db-&gt;from('urls');\r\n\t\t$this-&gt;db-&gt;where('id', (int) $id);\r\n\t\t\r\n\t\t$result = $this-&gt;db-&gt;get()-&gt;row_object();\r\n\r\n\t\t\/\/ check if the requested record was found\r\n\t\tif (count($result) &gt; 0) {\r\n\t\t\treturn $result;\r\n\t\t} else {\r\n\t\t\treturn FALSE;\r\n\t\t}\r\n\t}\r\n\t\r\n\t\r\n\tpublic function get_url( $alias )\r\n\t{\r\n\t\t$this-&gt;db-&gt;select('*');\r\n\t\t$this-&gt;db-&gt;from('urls');\r\n\t\t$this-&gt;db-&gt;where('alias', (string) $alias);\r\n\t\t\r\n\t\t$result = $this-&gt;db-&gt;get()-&gt;row_object();\r\n\r\n\t\t\/\/ check if the requested record was found\r\n\t\tif (count($result) &gt; 0) {\r\n\t\t\treturn $result;\r\n\t\t} else {\r\n\t\t\treturn FALSE;\r\n\t\t}\r\n\t}\r\n\r\n\r\n}<\/pre>\n<p>The <strong>get_url_by_id()<\/strong> and <strong>get_url()<\/strong> functions are identical except for retrieving different database fields.<\/p>\n<p>Once we have our primary model for the URLs, we load it as follows in the constructor for our home controller:<\/p>\n<pre class=\"lang:php decode:true\">&lt;?php\r\ndefined('BASEPATH') OR exit('No direct script access allowed');\r\n\r\nclass Home extends CI_Controller {\r\n\r\n\r\n\tpublic function __construct()\r\n\t{\r\n\t\tparent::__construct();\r\n\t\t\r\n\t\t\/\/ load models\r\n\t\t$this-&gt;load-&gt;model('Url_model');\r\n\t}\r\n<\/pre>\n<p>Now we can tackle the next step: creating our index page.<\/p>\n<p>To do so, we will define a data array with a few default values, and define logic for what should happen when a POST request arrives \u2013 in our case, a new URL should be created here with an alias:<\/p>\n<pre class=\"lang:default decode:true \">\tpublic function index()\r\n\t{\r\n\t\t$data = array(\r\n\t\t\t'error' =&gt; false,\r\n\t\t\t'show_details' =&gt; false,\r\n\t\t);\r\n\t\t$post = $this-&gt;input-&gt;post(NULL, TRUE);\r\n\r\n\t\t\/\/ check if request method was 'post' - if yes, then try to create short url\r\n\t\tif($post){\r\n\t\t\t$url = $post['url'];\r\n\t\t\t\r\n\t\t\t\/\/ validate url\r\n\t\t\tif (filter_var($url, FILTER_VALIDATE_URL)) {\r\n\t\t\t\t\r\n\t\t\t\t$id = $this-&gt;Url_model-&gt;add_url( $url );\r\n\t\t\t\t\r\n\t\t\t\t$url_data = $this-&gt;Url_model-&gt;get_url_by_id( $id );\r\n\t\t\t\t\r\n\t\t\t\t$data['show_details'] = true;\r\n\t\t\t\t$data['url_data'] = $url_data;\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t} else {\r\n\t\t\t\t$data['error'] = \"Invalid URL!\";\r\n\t\t\t}\r\n\t\t\t\r\n\t\t}\r\n\t\t\r\n\t\t\/\/ load view and assign data array\r\n\t\t$this-&gt;load-&gt;view('home', $data);\r\n\t}<\/pre>\n<p>In this example code, there is an additional PHP validation which checks that the URL submitted by the user is in fact a valid URL.<\/p>\n<p>If not, there could be unexpected side-effects during the redirect itself.<\/p>\n<p>Once the new URL has been stored in the database, this record is retrieved from there and passed to our view \u2013 after all, we want to show the user what their alias for the submitted URL looks like.<\/p>\n<p>In order to do this, however, we still need the associated home view (based on the <a href=\"http:\/\/getbootstrap.com\/\">Bootstrap framework<\/a>) in a file named <strong>\/application\/views\/home.php<\/strong>:<\/p>\n<pre class=\"lang:php decode:true \">&lt;?php defined('BASEPATH') OR exit('No direct script access allowed'); ?&gt;\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html lang=\"en\"&gt;\r\n\t&lt;head&gt;\r\n\t\t&lt;meta charset=\"utf-8\"&gt;\r\n\t\t&lt;meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"&gt;\r\n\t\t&lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\r\n\t\t&lt;meta name=\"description\" content=\"\"&gt;\r\n\t\t&lt;meta name=\"author\" content=\"\"&gt;\r\n\r\n\t\t&lt;title&gt;CI URL-Shortener&lt;\/title&gt;\r\n\r\n\t\t&lt;!-- Latest compiled and minified CSS --&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.7\/css\/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz\/K68vbdEjh4u\" crossorigin=\"anonymous\"&gt;\r\n\r\n\t\t&lt;!-- Custom CSS for basic styling --&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"&lt;?php echo base_url(); ?&gt;assets\/css\/style.css\" \/&gt;\r\n\t\t\r\n\t\t&lt;!-- Optional CSS for individual theming (powered by Bootswatch - https:\/\/bootswatch.com\/) --&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"&lt;?php echo base_url(); ?&gt;assets\/css\/bootstrap_flatly.min.css\" \/&gt;\r\n\r\n\t\t&lt;!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --&gt;\r\n\t\t&lt;!--[if lt IE 9]&gt;\r\n\t\t  &lt;script src=\"https:\/\/oss.maxcdn.com\/html5shiv\/3.7.3\/html5shiv.min.js\"&gt;&lt;\/script&gt;\r\n\t\t  &lt;script src=\"https:\/\/oss.maxcdn.com\/respond\/1.4.2\/respond.min.js\"&gt;&lt;\/script&gt;\r\n\t\t&lt;![endif]--&gt;\r\n\t\t&lt;\/head&gt;\r\n\t&lt;body&gt;\r\n\r\n\t&lt;nav class=\"navbar navbar-default navbar-fixed-top\"&gt;\r\n\t\t&lt;div class=\"container\"&gt;\r\n\t\t\t&lt;div class=\"navbar-header\"&gt;\r\n\t\t\t\t&lt;button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\" data-target=\"#navbar\" aria-expanded=\"false\" aria-controls=\"navbar\"&gt;\r\n\t\t\t\t\t&lt;span class=\"sr-only\"&gt;Toggle navigation&lt;\/span&gt;\r\n\t\t\t\t\t&lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n\t\t\t\t\t&lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n\t\t\t\t\t&lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n\t\t\t\t&lt;\/button&gt;\r\n\t\t\t\t&lt;a class=\"navbar-brand\" href=\"#\"&gt;CodeIgniter URL-Shortener&lt;\/a&gt;\r\n\t\t\t&lt;\/div&gt;\r\n\t\t\t&lt;div id=\"navbar\" class=\"collapse navbar-collapse\"&gt;\r\n\t\t\t\t&lt;ul class=\"nav navbar-nav\"&gt;\r\n\t\t\t\t\t&lt;li class=\"active\"&gt;&lt;a href=\"&lt;?php echo base_url(); ?&gt;\"&gt;Home&lt;\/a&gt;&lt;\/li&gt;\r\n\t\t\t\t\t&lt;li&gt;&lt;a href=\"#about\"&gt;About&lt;\/a&gt;&lt;\/li&gt;\r\n\t\t\t\t\t&lt;li&gt;&lt;a href=\"#contact\"&gt;Contact&lt;\/a&gt;&lt;\/li&gt;\r\n\t\t\t\t&lt;\/ul&gt;\r\n\t\t\t&lt;\/div&gt;\r\n\t\t&lt;\/div&gt;\r\n\t&lt;\/nav&gt;\r\n\r\n\t&lt;div class=\"container\"&gt;\r\n\r\n\t\t&lt;div class=\"intro\"&gt;\r\n\t\t\t&lt;h1&gt;My awesome URL shortener&lt;\/h1&gt;\r\n\t\t\t&lt;p class=\"lead\"&gt;\r\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, &lt;br\/&gt;\r\n\t\t\t\tsed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, &lt;br\/&gt;\r\n\t\t\t\tsed diam voluptua.\r\n\t\t\t&lt;\/p&gt;\r\n\t\t&lt;\/div&gt;\r\n\t\t\r\n\t\t&lt;?php echo form_open(); ?&gt;\r\n\t\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t\t&lt;div class=\"col-lg-8 col-lg-offset-2\"&gt;\r\n\t\t\t\t\t&lt;div class=\"input-group\"&gt;\r\n\t\t\t\t\t\t&lt;input type=\"url\" name=\"url\" class=\"form-control\" placeholder=\"Enter your URL here...\" autocomplete=\"off\" \/&gt;\r\n\t\t\t\t\t\t&lt;span class=\"input-group-btn\"&gt;\r\n\t\t\t\t\t\t\t&lt;button class=\"btn btn-default\" type=\"submit\"&gt;Go!&lt;\/button&gt;\r\n\t\t\t\t\t\t&lt;\/span&gt;\r\n\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\r\n\t\t\t\t\t&lt;?php if( $error ): ?&gt;\r\n\t\t\t\t\t&lt;p class=\"text-danger\"&gt;&lt;?php echo $error; ?&gt;&lt;\/p&gt;\r\n\t\t\t\t\t&lt;?php endif; ?&gt;\r\n\t\t\t\t&lt;\/div&gt;\r\n\t\t\t&lt;\/div&gt;\r\n\t\t&lt;?php echo form_close(); ?&gt;\r\n\t\t\r\n\t\t&lt;?php if( $show_details ): ?&gt;\r\n\t\t&lt;div class=\"well url_data\"&gt;\r\n\t\t\t&lt;h2&gt;Your new created Short-URL:&lt;\/h2&gt;\r\n\t\t\t\r\n\t\t\t&lt;div class=\"input-group\"&gt;\r\n\t\t\t\t&lt;input type=\"text\" value=\"&lt;?php echo base_url( $url_data-&gt;alias ); ?&gt;\" class=\"form-control input-lg\" readonly=\"readonly\" \/&gt;\r\n\t\t\t\t&lt;span class=\"input-group-btn\"&gt;\r\n\t\t\t\t\t&lt;a href=\"&lt;?php echo base_url( $url_data-&gt;alias ); ?&gt;\" class=\"btn btn-default btn-lg\" target=\"_blank\"&gt;\r\n\t\t\t\t\t\t&lt;span class=\"glyphicon glyphicon-share-alt\" aria-hidden=\"true\"&gt;&lt;\/span&gt;\r\n\t\t\t\t\t&lt;\/a&gt;\r\n\t\t\t\t&lt;\/span&gt;\r\n\t\t\t&lt;\/div&gt;\r\n\t\t\t\r\n\t\t\t&lt;p&gt;&amp;nbsp;&lt;\/p&gt;\r\n\t\t\t&lt;p&gt;You can view statistics for this URL here: &lt;a href=\"&lt;?php echo base_url( $url_data-&gt;alias .'\/stats' ); ?&gt;\" target=\"_blank\"&gt;&lt;?php echo base_url( $url_data-&gt;alias .'\/stats' ); ?&gt;&lt;\/a&gt;&lt;\/p&gt;\r\n\t\t\t\r\n\t\t&lt;\/div&gt;\r\n\t\t&lt;?php endif; ?&gt;\r\n\r\n\t&lt;\/div&gt;\r\n\r\n\r\n\t&lt;!-- Bootstrap core JavaScript\r\n\t================================================== --&gt;\r\n\t&lt;!-- Placed at the end of the document so the pages load faster --&gt;\r\n\t&lt;script type=\"text\/javascript\" src=\"https:\/\/code.jquery.com\/jquery-3.2.1.min.js\" integrity=\"sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n\t&lt;script type=\"text\/javascript\" src=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.7\/js\/bootstrap.min.js\" integrity=\"sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n\t&lt;\/body&gt;\r\n\t&lt;\/html&gt;\r\n<\/pre>\n<p>The linked <strong>bootstrap_flatly.min.css<\/strong> file is the free &#8222;<a href=\"https:\/\/bootswatch.com\/flatly\/\">Flatly<\/a>&#8220; Bootstrap theme from <a href=\"https:\/\/bootswatch.com\/\">Bootswatch<\/a>.<br \/>\nThis CSS theme is optional and can therefore be left out if you prefer.<\/p>\n<p>In the <strong>style.css<\/strong> file, we will define only a few basic styles:<\/p>\n<pre class=\"lang:css decode:true \">body {\r\n\tpadding-top: 50px;\r\n}\r\n.intro {\r\n\tpadding: 40px 15px;\r\n\ttext-align: center;\r\n}\r\n\r\n.intro h1 {\r\n\tmargin-bottom: 40px;\r\n}\r\n\r\n.url_data {\r\n\tmargin-top: 60px;\r\n\ttext-align: center;\r\n}\r\n\r\n.url_data h2 {\r\n\tfont-size: 25px;\r\n}<\/pre>\n<p>The home view itself merely provides a form to submit a URL, and an area below to display the generated alias.<\/p>\n<p>Now we can test our application for the first time by entering any URL into the form and submitting it.<br \/>\nWe should now be able to find this URL in the database along with an alias, which should be displayed to us on the index page underneath the form.<\/p>\n<p>&nbsp;<\/p>\n<h3>CONFIGURE REDIRECT<\/h3>\n<p>Because we also want to analyze the requests received by our system instead of simply redirecting to the destination URL, we will now create a model for the statistics table. To do so, navigate to <strong>\/application\/models<\/strong> and create a new file named<strong> Statistics_model.php<\/strong> with the following content:<\/p>\n<pre class=\"lang:default decode:true \">&lt;?php\r\ndefined('BASEPATH') OR exit('No direct script access allowed');\r\n\r\nclass Statistics_model extends CI_Model {\r\n\t\r\n\t\r\n\tfunction add_log( $url_id )\r\n\t{\r\n\t\t\/\/ build up data array\r\n\t\t$data = array(\r\n\t\t\t'url_id'\t\t=&gt; (int) $url_id,\r\n\t\t\t'created'\t=&gt; date('Y-m-d H:i:s'),\r\n\t\t);\r\n\t\t \r\n\t\t\/\/ inserts the data into database\r\n\t\t$this-&gt;db-&gt;insert('statistics', $data);\r\n\t\t\r\n\t\t\/\/ return this ID of the new inserted record\r\n\t\treturn $this-&gt;db-&gt;insert_id();\r\n\t}\r\n\t\r\n\t\r\n\tpublic function get_logs( $url_id )\r\n\t{\r\n\t\t$this-&gt;db-&gt;select( array('*', 'COUNT(id) AS sum') );\r\n\t\t$this-&gt;db-&gt;from('statistics');\r\n\t\t$this-&gt;db-&gt;where('url_id', (int) $url_id);\r\n\t\t$this-&gt;db-&gt;group_by('DATE_FORMAT(created, \"%m-%y-%d\")');\r\n\t\t$this-&gt;db-&gt;order_by('YEAR(created) ASC, MONTH(created) ASC, DAY(created) ASC');\r\n\t\t\r\n\t\t$result = $this-&gt;db-&gt;get()-&gt;result_object();\r\n\r\n\t\t\/\/ check if the requested record was found\r\n\t\tif (count($result) &gt; 0) {\r\n\t\t\treturn $result;\r\n\t\t} else {\r\n\t\t\treturn FALSE;\r\n\t\t}\r\n\t}\r\n\t\r\n\r\n}<\/pre>\n<p>The functions here are limited to creating a new entry for a particular URL (with <strong>add_log()<\/strong>), and retrieving all entries for a URL (with <strong>get_logs()<\/strong>).<\/p>\n<p>In the latter case, entries are grouped by date and the total number of times the URL was accessed per day is returned as a <em>sum<\/em>.<\/p>\n<p>Load this model in the home controller constructor in the same way as the URL model:<\/p>\n<pre class=\"lang:php decode:true \">&lt;?php\r\ndefined('BASEPATH') OR exit('No direct script access allowed');\r\n\r\nclass Home extends CI_Controller {\r\n\r\n\r\n\tpublic function __construct()\r\n\t{\r\n\t\tparent::__construct();\r\n\t\t\r\n\t\t\/\/ load models\r\n\t\t$this-&gt;load-&gt;model('Url_model');\r\n\t\t$this-&gt;load-&gt;model('Statistics_model');\r\n\t}<\/pre>\n<p>Having defined an empty \u201c<em>redirect<\/em>\u201d action earlier, it is now time to give this a function too.<\/p>\n<p>The parameter passed on as <em>$alias<\/em> is the one that was previously generated when the URL was stored.<\/p>\n<p>This is now used to search the database for the desired entry with the help of the <strong>get_url()<\/strong> function we created before.<\/p>\n<pre class=\"lang:php decode:true\">\tpublic function redirect( $alias )\r\n\t{\r\n\t\t$url_data = $this-&gt;Url_model-&gt;get_url( $alias );\r\n\t\t\r\n\t\t\/\/ check if there's an url with this alias\r\n\t\tif(!$url_data){\r\n\t\t\r\n\t\t\theader(\"HTTP\/1.0 404 Not Found\");\r\n\t\t\t$this-&gt;load-&gt;view('not_found');\r\n\t\t\r\n\t\t}else{\r\n\t\t\t\r\n\t\t\t$this-&gt;Statistics_model-&gt;add_log( $url_data-&gt;id );\r\n\t\t\t\r\n\t\t\theader('Location: ' . $url_data-&gt;url, true, 302);\r\n\t\t\texit();\r\n\t\t}\r\n\t\t\r\n\t}<\/pre>\n<p>When the appropriate database entry has been found, we can carry out the actual redirect using the location header.<\/p>\n<p>(The \u201c302\u201d at the end indicates the accompanying HTTP status code. Of course, this would usually be a \u201c301\u201d (preferable in production systems from an SEO perspective) \u2013 but since redirects with a 301 header are cached by the browser, this would be highly impractical for testing, so in this case it is \u201c302\u201d.)<\/p>\n<p>Before this redirect, however, we still want to our statistics model to store a record of access to the URL.<\/p>\n<p>It is therefore important that there is no other output after the location header (or generally after a header output) \u2013 so we will add an <strong>exit()<\/strong> afterwards as a precaution.<br \/>\nIn the event that no database entry is found for an alias, we simply refer to a \u201cnot found\u201d view:<\/p>\n<pre class=\"lang:php decode:true\">&lt;?php defined('BASEPATH') OR exit('No direct script access allowed'); ?&gt;\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html lang=\"en\"&gt;\r\n\t&lt;head&gt;\r\n\t\t&lt;meta charset=\"utf-8\"&gt;\r\n\t\t&lt;meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"&gt;\r\n\t\t&lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\r\n\t\t&lt;meta name=\"description\" content=\"\"&gt;\r\n\t\t&lt;meta name=\"author\" content=\"\"&gt;\r\n\r\n\t\t&lt;title&gt;CI URL-Shortener&lt;\/title&gt;\r\n\r\n\t\t&lt;!-- Latest compiled and minified CSS --&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.7\/css\/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz\/K68vbdEjh4u\" crossorigin=\"anonymous\"&gt;\r\n\r\n\t\t&lt;!-- Custom CSS for basic styling --&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"&lt;?php echo base_url(); ?&gt;assets\/css\/style.css\" \/&gt;\r\n\t\t\r\n\t\t&lt;!-- Optional CSS for individual theming (powered by Bootswatch - https:\/\/bootswatch.com\/) --&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"&lt;?php echo base_url(); ?&gt;assets\/css\/bootstrap_flatly.min.css\" \/&gt;\r\n\r\n\t\t&lt;!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --&gt;\r\n\t\t&lt;!--[if lt IE 9]&gt;\r\n\t\t  &lt;script src=\"https:\/\/oss.maxcdn.com\/html5shiv\/3.7.3\/html5shiv.min.js\"&gt;&lt;\/script&gt;\r\n\t\t  &lt;script src=\"https:\/\/oss.maxcdn.com\/respond\/1.4.2\/respond.min.js\"&gt;&lt;\/script&gt;\r\n\t\t&lt;![endif]--&gt;\r\n\t\t&lt;\/head&gt;\r\n\t&lt;body&gt;\r\n\r\n\t&lt;nav class=\"navbar navbar-default navbar-fixed-top\"&gt;\r\n\t\t&lt;div class=\"container\"&gt;\r\n\t\t\t&lt;div class=\"navbar-header\"&gt;\r\n\t\t\t\t&lt;button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\" data-target=\"#navbar\" aria-expanded=\"false\" aria-controls=\"navbar\"&gt;\r\n\t\t\t\t\t&lt;span class=\"sr-only\"&gt;Toggle navigation&lt;\/span&gt;\r\n\t\t\t\t\t&lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n\t\t\t\t\t&lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n\t\t\t\t\t&lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n\t\t\t\t&lt;\/button&gt;\r\n\t\t\t\t&lt;a class=\"navbar-brand\" href=\"#\"&gt;CodeIgniter URL-Shortener&lt;\/a&gt;\r\n\t\t\t&lt;\/div&gt;\r\n\t\t\t&lt;div id=\"navbar\" class=\"collapse navbar-collapse\"&gt;\r\n\t\t\t\t&lt;ul class=\"nav navbar-nav\"&gt;\r\n\t\t\t\t\t&lt;li&gt;&lt;a href=\"&lt;?php echo base_url(); ?&gt;\"&gt;Home&lt;\/a&gt;&lt;\/li&gt;\r\n\t\t\t\t\t&lt;li&gt;&lt;a href=\"#about\"&gt;About&lt;\/a&gt;&lt;\/li&gt;\r\n\t\t\t\t\t&lt;li&gt;&lt;a href=\"#contact\"&gt;Contact&lt;\/a&gt;&lt;\/li&gt;\r\n\t\t\t\t&lt;\/ul&gt;\r\n\t\t\t&lt;\/div&gt;\r\n\t\t&lt;\/div&gt;\r\n\t&lt;\/nav&gt;\r\n\r\n\t&lt;div class=\"container\"&gt;\r\n\r\n\t\t&lt;div class=\"intro\"&gt;\r\n\t\t\t&lt;h1&gt;Whoops! Something went wrong...&lt;\/h1&gt;\r\n\t\t\t&lt;p class=\"lead\"&gt;\r\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, &lt;br\/&gt;\r\n\t\t\t\tsed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, &lt;br\/&gt;\r\n\t\t\t\tsed diam voluptua.\r\n\t\t\t&lt;\/p&gt;\r\n\t\t&lt;\/div&gt;\r\n\t\t\r\n\r\n\t&lt;\/div&gt;\r\n\r\n\r\n\t&lt;!-- Bootstrap core JavaScript\r\n\t================================================== --&gt;\r\n\t&lt;!-- Placed at the end of the document so the pages load faster --&gt;\r\n\t&lt;script type=\"text\/javascript\" src=\"https:\/\/code.jquery.com\/jquery-3.2.1.min.js\" integrity=\"sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n\t&lt;script type=\"text\/javascript\" src=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.7\/js\/bootstrap.min.js\" integrity=\"sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n\t&lt;\/body&gt;\r\n\t&lt;\/html&gt;<\/pre>\n<p>This view is stored in a file named <strong>\/application\/views\/not_found.php<\/strong>. It can be customized, and in our case it has no particular function.<\/p>\n<p>The short URL previously generated in the last test can now be tested \u2013 if we have done everything correctly, it will redirect to the destination URL and an access log entry will be stored in the statistics table.<\/p>\n<p>&nbsp;<\/p>\n<h3>SHOW STATISTICS<\/h3>\n<p>At first glance, the \u201c<em>stats<\/em>\u201d action looks like the \u201c<em>redirect<\/em>\u201d action. This is due to them working in a similar way: both carry out a database search using a transferred alias.<\/p>\n<p>The \u201c<em>redirect<\/em>\u201d action results in a redirect, and the \u201c<em>stats<\/em>\u201d action uses this data to retrieve all existing log entries for this URL.<\/p>\n<pre class=\"lang:default decode:true \">\tpublic function stats( $alias )\r\n\t{\r\n\t\t$url_data = $this-&gt;Url_model-&gt;get_url( $alias );\r\n\t\t\r\n\t\t\/\/ check if there's an url with this alias\r\n\t\tif(!$url_data){\r\n\r\n\t\t\theader(\"HTTP\/1.0 404 Not Found\");\r\n\t\t\t$this-&gt;load-&gt;view('not_found');\r\n\r\n\t\t}else{\r\n\t\t\t\r\n\t\t\t$logs = $this-&gt;Statistics_model-&gt;get_logs( $url_data-&gt;id );\r\n\t\t\t\r\n\t\t\t$data = array(\r\n\t\t\t\t'url_data'\t=&gt; $url_data,\r\n\t\t\t\t'logs'\t\t=&gt; $logs,\r\n\t\t\t);\r\n\t\t\t\r\n\t\t\t$this-&gt;load-&gt;view('stats', $data);\r\n\r\n\t\t}\r\n\t\t\r\n\t}<\/pre>\n<p>Once again, our \u201cnot found\u201d view from above is used in the event that no database entry is found for a particular alias.<\/p>\n<p>The associated view (<strong>\/application\/views\/stats.php<\/strong>) would then look as follows:<\/p>\n<pre class=\"lang:php decode:true \">&lt;?php defined('BASEPATH') OR exit('No direct script access allowed'); ?&gt;\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html lang=\"en\"&gt;\r\n\t&lt;head&gt;\r\n\t\t&lt;meta charset=\"utf-8\"&gt;\r\n\t\t&lt;meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"&gt;\r\n\t\t&lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\r\n\t\t&lt;meta name=\"description\" content=\"\"&gt;\r\n\t\t&lt;meta name=\"author\" content=\"\"&gt;\r\n\r\n\t\t&lt;title&gt;CI URL-Shortener&lt;\/title&gt;\r\n\r\n\t\t&lt;!-- Latest compiled and minified CSS --&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.7\/css\/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz\/K68vbdEjh4u\" crossorigin=\"anonymous\"&gt;\r\n\r\n\t\t&lt;!-- Custom CSS for basic styling --&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"&lt;?php echo base_url(); ?&gt;assets\/css\/style.css\" \/&gt;\r\n\t\t\r\n\t\t&lt;!-- Optional CSS for individual theming (powered by Bootswatch - https:\/\/bootswatch.com\/) --&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"&lt;?php echo base_url(); ?&gt;assets\/css\/bootstrap_flatly.min.css\" \/&gt;\r\n\r\n\t\t&lt;!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --&gt;\r\n\t\t&lt;!--[if lt IE 9]&gt;\r\n\t\t  &lt;script src=\"https:\/\/oss.maxcdn.com\/html5shiv\/3.7.3\/html5shiv.min.js\"&gt;&lt;\/script&gt;\r\n\t\t  &lt;script src=\"https:\/\/oss.maxcdn.com\/respond\/1.4.2\/respond.min.js\"&gt;&lt;\/script&gt;\r\n\t\t&lt;![endif]--&gt;\r\n\t\t&lt;\/head&gt;\r\n\t&lt;body&gt;\r\n\r\n\t&lt;nav class=\"navbar navbar-default navbar-fixed-top\"&gt;\r\n\t\t&lt;div class=\"container\"&gt;\r\n\t\t\t&lt;div class=\"navbar-header\"&gt;\r\n\t\t\t\t&lt;button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\" data-target=\"#navbar\" aria-expanded=\"false\" aria-controls=\"navbar\"&gt;\r\n\t\t\t\t\t&lt;span class=\"sr-only\"&gt;Toggle navigation&lt;\/span&gt;\r\n\t\t\t\t\t&lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n\t\t\t\t\t&lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n\t\t\t\t\t&lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n\t\t\t\t&lt;\/button&gt;\r\n\t\t\t\t&lt;a class=\"navbar-brand\" href=\"#\"&gt;CodeIgniter URL-Shortener&lt;\/a&gt;\r\n\t\t\t&lt;\/div&gt;\r\n\t\t\t&lt;div id=\"navbar\" class=\"collapse navbar-collapse\"&gt;\r\n\t\t\t\t&lt;ul class=\"nav navbar-nav\"&gt;\r\n\t\t\t\t\t&lt;li&gt;&lt;a href=\"&lt;?php echo base_url(); ?&gt;\"&gt;Home&lt;\/a&gt;&lt;\/li&gt;\r\n\t\t\t\t\t&lt;li&gt;&lt;a href=\"#about\"&gt;About&lt;\/a&gt;&lt;\/li&gt;\r\n\t\t\t\t\t&lt;li&gt;&lt;a href=\"#contact\"&gt;Contact&lt;\/a&gt;&lt;\/li&gt;\r\n\t\t\t\t&lt;\/ul&gt;\r\n\t\t\t&lt;\/div&gt;\r\n\t\t&lt;\/div&gt;\r\n\t&lt;\/nav&gt;\r\n\r\n\t&lt;div class=\"container\"&gt;\r\n\r\n\t\t&lt;div class=\"intro\"&gt;\r\n\t\t\t&lt;h1&gt;Statistics for URL&lt;\/h1&gt;\r\n\t\t\t&lt;p class=\"lead\"&gt;\r\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, &lt;br\/&gt;\r\n\t\t\t\tsed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, &lt;br\/&gt;\r\n\t\t\t\tsed diam voluptua.\r\n\t\t\t&lt;\/p&gt;\r\n\t\t&lt;\/div&gt;\r\n\t\t\r\n\t\t&lt;div class=\"well\"&gt;\t\t\r\n\t\t\t&lt;h3&gt;&lt;?php echo $url_data-&gt;url; ?&gt;&lt;\/h3&gt;\r\n\t\t\t&lt;p class=\"help-block\"&gt;Created: &lt;?php echo $url_data-&gt;created; ?&gt;&lt;\/p&gt;\r\n\t\t&lt;\/div&gt;\r\n\r\n\t\t\r\n\t\t&lt;?php if($logs): ?&gt;\r\n\t\t\r\n\t\t&lt;table class=\"table table-striped\"&gt;\r\n\t\t\t&lt;thead&gt;\r\n\t\t\t\t&lt;tr&gt;\r\n\t\t\t\t\t&lt;th&gt;Date&lt;\/th&gt;\r\n\t\t\t\t\t&lt;th&gt;Number of clicks&lt;\/th&gt;\r\n\t\t\t\t&lt;\/tr&gt;\r\n\t\t\t&lt;\/thead&gt;\r\n\t\t\t&lt;tbody&gt;\r\n\t\t\t\t&lt;?php foreach($logs as $log): ?&gt;\r\n\t\t\t\t&lt;tr&gt;\r\n\t\t\t\t\t&lt;th&gt;&lt;?php echo date('Y-m-d', strtotime( $log-&gt;created )); ?&gt;&lt;\/th&gt;\r\n\t\t\t\t\t&lt;th&gt;&lt;?php echo $log-&gt;sum; ?&gt;&lt;\/th&gt;\r\n\t\t\t\t&lt;\/tr&gt;\r\n\t\t\t\t&lt;?php endforeach; ?&gt;\r\n\t\t\t&lt;\/tbody&gt;\r\n\t\t&lt;\/table&gt;\r\n\t\t\r\n\t\t&lt;?php else: ?&gt;\r\n\t\t\r\n\t\t&lt;div class=\"alert alert-warning\"&gt;\r\n\t\t\t&lt;p&gt;Unfortunately, there're no statistics available.\r\n\t\t&lt;\/div&gt;\r\n\t\t\r\n\t\t&lt;?php endif; ?&gt;\r\n\t\t\t\t\r\n\r\n\t&lt;\/div&gt;\r\n\r\n\r\n\t&lt;!-- Bootstrap core JavaScript\r\n\t================================================== --&gt;\r\n\t&lt;!-- Placed at the end of the document so the pages load faster --&gt;\r\n\t&lt;script type=\"text\/javascript\" src=\"https:\/\/code.jquery.com\/jquery-3.2.1.min.js\" integrity=\"sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n\t&lt;script type=\"text\/javascript\" src=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.7\/js\/bootstrap.min.js\" integrity=\"sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n\t&lt;\/body&gt;\r\n\t&lt;\/html&gt;\r\n<\/pre>\n<p>We iterate over all existing log entries for it in a <em>foreach<\/em> loop and show them in table format.<\/p>\n<p>If preferred, this data can also be displayed as a diagram. There are numerous jQuery plugins for this on the Internet.<\/p>\n<p>In the event that there are no log entries (if, for example, the short URL has never been accessed), a note to this effect will be shown.<\/p>\n<p>&nbsp;<\/p>\n<h2>CONCLUSION<\/h2>\n<p>Short URL services are very simple in structure. Their use is not always simple, however, and they can also be misused since end users cannot clearly see where they will be redirected.<\/p>\n<p>Although some major providers already have quite good protection against malware and phishing, security remains controversial despite its relatively high standards.<\/p>\n<p>The possible tracking option (limited in this tutorial to logging access) can also be expanded at will \u2013 e.g. to include capturing a user\u2019s IP (if possible, it would be advisable for privacy reasons not to store the last part of the IP or to anonymize it), and as a result their country (using GeoIP) or any referrers, etc.<\/p>\n<p>The analysis of such data is especially important in marketing, as this allows advertising campaigns etc. to be targeted more specifically and made more cost-effective. For this reason, these short URL services are of particular interest to businesses. Short URLs of this kind are used in things like newsletters, for example, to find out how often a link was clicked. \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mit Codigniter zum eigenen URL-Shortener? Manuel Wutte, Softwarenentwickler bei Anexia erkl\u00e4rt in seinem Tutorial, wie das geht.<\/p>\n","protected":false},"author":15,"featured_media":515,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1135],"tags":[1657,1614,1570,1699],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Setting up your custom URL shortener (incl. statistics) with CodeIgniter - ANEXIA Blog<\/title>\n<meta name=\"description\" content=\"Mit Codigniter zum eigenen URL-Shortener? Manuel Wutte, Softwarenentwickler bei Anexia erkl\u00e4rt in seinem Tutorial, wie das geht.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Setting up your custom URL shortener (incl. statistics) with CodeIgniter - ANEXIA Blog\" \/>\n<meta property=\"og:description\" content=\"Mit Codigniter zum eigenen URL-Shortener? Manuel Wutte, Softwarenentwickler bei Anexia erkl\u00e4rt in seinem Tutorial, wie das geht.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/\" \/>\n<meta property=\"og:site_name\" content=\"ANEXIA Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/anexiagmbh\/\" \/>\n<meta property=\"article:published_time\" content=\"2017-07-10T11:25:15+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-04-21T12:23:28+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/Manuel-Wutte_anexia-blau_web.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1600\" \/>\n\t<meta property=\"og:image:height\" content=\"1067\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Manuel Wutte\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@_ANEXIA\" \/>\n<meta name=\"twitter:site\" content=\"@_ANEXIA\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manuel Wutte\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"23\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/\",\"url\":\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/\",\"name\":\"Setting up your custom URL shortener (incl. statistics) with CodeIgniter - ANEXIA Blog\",\"isPartOf\":{\"@id\":\"https:\/\/anexia.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/Manuel-Wutte_anexia-blau_web.jpg\",\"datePublished\":\"2017-07-10T11:25:15+00:00\",\"dateModified\":\"2022-04-21T12:23:28+00:00\",\"author\":{\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de\"},\"description\":\"Mit Codigniter zum eigenen URL-Shortener? Manuel Wutte, Softwarenentwickler bei Anexia erkl\u00e4rt in seinem Tutorial, wie das geht.\",\"breadcrumb\":{\"@id\":\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#primaryimage\",\"url\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/Manuel-Wutte_anexia-blau_web.jpg\",\"contentUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/Manuel-Wutte_anexia-blau_web.jpg\",\"width\":1600,\"height\":1067},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/anexia.com\/blog\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Setting up your custom URL shortener (incl. statistics) with CodeIgniter\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/anexia.com\/blog\/#website\",\"url\":\"https:\/\/anexia.com\/blog\/\",\"name\":\"ANEXIA Blog\",\"description\":\"[:de] ANEXIA Blog - Technischen Themen, Anexia News und Insights [:]\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/anexia.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de\",\"name\":\"Manuel Wutte\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g\",\"caption\":\"Manuel Wutte\"},\"url\":\"https:\/\/anexia.com\/blog\/author\/mwu\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Setting up your custom URL shortener (incl. statistics) with CodeIgniter - ANEXIA Blog","description":"Mit Codigniter zum eigenen URL-Shortener? Manuel Wutte, Softwarenentwickler bei Anexia erkl\u00e4rt in seinem Tutorial, wie das geht.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/","og_locale":"de_DE","og_type":"article","og_title":"Setting up your custom URL shortener (incl. statistics) with CodeIgniter - ANEXIA Blog","og_description":"Mit Codigniter zum eigenen URL-Shortener? Manuel Wutte, Softwarenentwickler bei Anexia erkl\u00e4rt in seinem Tutorial, wie das geht.","og_url":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/","og_site_name":"ANEXIA Blog","article_publisher":"https:\/\/www.facebook.com\/anexiagmbh\/","article_published_time":"2017-07-10T11:25:15+00:00","article_modified_time":"2022-04-21T12:23:28+00:00","og_image":[{"width":1600,"height":1067,"url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/Manuel-Wutte_anexia-blau_web.jpg","type":"image\/jpeg"}],"author":"Manuel Wutte","twitter_card":"summary_large_image","twitter_creator":"@_ANEXIA","twitter_site":"@_ANEXIA","twitter_misc":{"Verfasst von":"Manuel Wutte","Gesch\u00e4tzte Lesezeit":"23\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/","url":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/","name":"Setting up your custom URL shortener (incl. statistics) with CodeIgniter - ANEXIA Blog","isPartOf":{"@id":"https:\/\/anexia.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#primaryimage"},"image":{"@id":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#primaryimage"},"thumbnailUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/Manuel-Wutte_anexia-blau_web.jpg","datePublished":"2017-07-10T11:25:15+00:00","dateModified":"2022-04-21T12:23:28+00:00","author":{"@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de"},"description":"Mit Codigniter zum eigenen URL-Shortener? Manuel Wutte, Softwarenentwickler bei Anexia erkl\u00e4rt in seinem Tutorial, wie das geht.","breadcrumb":{"@id":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#primaryimage","url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/Manuel-Wutte_anexia-blau_web.jpg","contentUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/Manuel-Wutte_anexia-blau_web.jpg","width":1600,"height":1067},{"@type":"BreadcrumbList","@id":"https:\/\/anexia.com\/blog\/en\/setting-up-your-custom-url-shortener-incl-statistics-with-codeigniter\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/anexia.com\/blog\/de\/"},{"@type":"ListItem","position":2,"name":"Setting up your custom URL shortener (incl. statistics) with CodeIgniter"}]},{"@type":"WebSite","@id":"https:\/\/anexia.com\/blog\/#website","url":"https:\/\/anexia.com\/blog\/","name":"ANEXIA Blog","description":"[:de] ANEXIA Blog - Technischen Themen, Anexia News und Insights [:]","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/anexia.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de","name":"Manuel Wutte","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g","caption":"Manuel Wutte"},"url":"https:\/\/anexia.com\/blog\/author\/mwu\/"}]}},"lang":"en","translations":{"en":6803,"de":2696},"amp_enabled":true,"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/6803"}],"collection":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/comments?post=6803"}],"version-history":[{"count":1,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/6803\/revisions"}],"predecessor-version":[{"id":6806,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/6803\/revisions\/6806"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media\/515"}],"wp:attachment":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media?parent=6803"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/categories?post=6803"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/tags?post=6803"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}