{"id":2939,"date":"2017-09-21T14:39:34","date_gmt":"2017-09-21T14:39:34","guid":{"rendered":"https:\/\/anexia.com\/blog\/de\/?p=2939"},"modified":"2022-04-19T09:11:22","modified_gmt":"2022-04-19T07:11:22","slug":"mit-codeigniter-und-curl-den-download-speed-drosseln","status":"publish","type":"post","link":"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/","title":{"rendered":"Mit CodeIgniter und cURL den Download-Speed drosseln"},"content":{"rendered":"<p>Viele Webseiten, insbesondere Download-Portale,\u00a0 sind bekannt daf\u00fcr, dass sie die Download-Geschwindigkeit von Dateien (zum Teil sehr stark) drosseln. Meistens beruht darauf deren Gesch\u00e4ftsmodell, indem man die volle Download-Geschwindigkeit nur dann bekommt, wenn man daf\u00fcr bezahlt.<br \/>\nIn diesem Tutorial m\u00f6chte ich euch zeigen, was dahinter steckt und wie diese Anbieter hier softwareseitig tricksen. Dazu zeige ich hier, wie man eine solche Download-Drosselung in ein CodeIgniter-Projekt integriert.<\/p>\n<p><a href=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ci-downloadspeed.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-2940\" src=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ci-downloadspeed-1024x518.png\" alt=\"Download-Speed-Drosselung mit CodeIgniter\" width=\"599\" height=\"303\" srcset=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ci-downloadspeed-1024x518.png 1024w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ci-downloadspeed-325x164.png 325w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ci-downloadspeed-300x152.png 300w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ci-downloadspeed-768x388.png 768w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ci-downloadspeed.png 1920w\" sizes=\"(max-width: 599px) 100vw, 599px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<h2>cURL als Kern der Anwendung<\/h2>\n<p>Bei <a href=\"https:\/\/curl.haxx.se\/\" target=\"_blank\" rel=\"noopener\">cURL <\/a>handelt es sich um eine weit verbreitete Kommandozeilenanwendung, welche speziell f\u00fcr das \u00dcbertragen von Daten innerhalb von Computernetzwerken ausgelegt ist. Der Vorteil liegt in der einfachen Verwendung, denn die\u00a0Programmbibliothek wurde f\u00fcr so ziemlich alle Betriebssysteme portiert. Au\u00dferdem hat sie einen immensen Funktionsumfang.<\/p>\n<p>Im Vergleich zum \u00e4lteren Vorg\u00e4nger &#8222;wget&#8220; beherrscht cURL nicht nur das Herunter-, sondern auch das Hochladen von Dateien. Zahlreiche Parameter bieten daf\u00fcr entsprechend viele Optionen, um so gut wie jedes Szenario abdecken zu k\u00f6nnen.<\/p>\n<p>&nbsp;<\/p>\n<h2>Setup mit CodeIgniter<\/h2>\n<p>Nun kommen wir zum wesentlichen Teil dieses Tutorials &#8211; dem Einbau einer Speed-Drosselung in ein CodeIgniter-Projekt.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-504\" src=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2015\/01\/codeigniter_logo-300x70.png\" alt=\"CodeIgniter Logo\" width=\"599\" height=\"140\" 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: 599px) 100vw, 599px\" \/><\/p>\n<p>&nbsp;<\/p>\n<h2>Schritt 1: Basissystem vorbereiten<\/h2>\n<p>Um mit unserem Projekt starten zu k\u00f6nnen, erstellen wir zun\u00e4chst die Basis, auf der wir anschlie\u00dfend aufbauen k\u00f6nnen. Dazu laden wir uns von der <a href=\"https:\/\/www.codeigniter.com\">CodeIgniter-Homepage<\/a> die aktuellste Version des Frameworks herunter. Dies w\u00e4re in diesem Fall Version 3.1.5.<\/p>\n<p>Nun kopieren wir alle Dateien am besten in einen Unterordner \u201eci-downloadspeed\u201c auf den Webserver (z.B. XAMPP, LAMP, etc.) und rufen dessen Rootverzeichnis im Browser auf, z.B. http:\/\/localhost\/ci-downloadspeed\/. Wenn alle Anforderungen des Frameworks erf\u00fcllt sind, sollte hier nun die Willkommensseite von CodeIgniter sichtbar sein.<\/p>\n<p>Damit die Speaking-URLs auch korrekt aufgerufen werden k\u00f6nnen, legen wir uns eine <strong>.htaccess<\/strong> mit folgendem Inhalt an:<\/p>\n<pre class=\"lang:default decode:true\">RewriteEngine on\r\n\r\nRewriteRule ^(assets|downloads)($|\/) - [L]\r\nRewriteRule .* index.php<\/pre>\n<p>Im Verzeichnis &#8222;<em>assets<\/em>&#8220; werden wir alle Ressourcen ablegen, die\u00a0wir f\u00fcr die eigentliche Applikation brauchen werden (CSS und JS-Dateien), im Verzeichnis &#8222;<em>downloads<\/em>&#8220; kommen sp\u00e4ter unsere Beispiel-Download-Dateien hinein (Infos dazu befinden sich im Abschnitt &#8222;Fazit&#8220;).<\/p>\n<p>In der Autoloader-Konfiguration unter <strong>\/application\/config\/autoload.php<\/strong> f\u00fcgen wir anschlie\u00dfend den URL-Helper hinzu. Damit k\u00f6nnen wir einerseits im Frontend, und anderseits diesmal auch innerhalb der Applikation selbst die <em>base_url()<\/em>-Funktion nutzen.<\/p>\n<pre class=\"lang:php decode:true\">$autoload['helper'] = array('url');<\/pre>\n<p>In der Routenkonfiguration unter <strong>\/application\/config\/routes.php<\/strong> \u00e4ndern wir als danach den Standard-Controller von \u201e<em>welcome<\/em>\u201c auf \u201e<em>home<\/em>\u201c, da wir m\u00f6chten, dass standardm\u00e4\u00dfig unsere Speed-Drosselungs-Applikation aufgerufen wird.<\/p>\n<pre class=\"lang:php decode:true\">$route['default_controller'] = 'home';\r\n$route['404_override'] = '';\r\n$route['translate_uri_dashes'] = FALSE;<\/pre>\n<p>&nbsp;<\/p>\n<h2>Schritt 2: Grundlayout definieren<\/h2>\n<p>Dazu erstellen wir unter <strong>\/application\/controller <\/strong>eine<strong> Home.php<\/strong> (Gro\u00df-\/Kleinschreibung beachten!).<br \/>\nIn dieser legen wir als n\u00e4chstes das Grundger\u00fcst unserer Applikation an &#8211; dies w\u00e4ren zwei Actions: eine f\u00fcr die Index-Seite und eine f\u00fcr die gedrosselten Datei-Downloads. Letztere bekommt noch Parameter f\u00fcr den Typ des Downloads (in unserem Beispiel zur Unterscheidung zwischen einer kleinen und einer gro\u00dfen Datei), sowie f\u00fcr den Download-Speed selbst (in KB\/s).<\/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\r\n\tpublic function index()\r\n\t{\r\n\t\t\r\n\t}\r\n\r\n\r\n\tpublic function download($type = 1, $speed_kbs = 64)\r\n\t{\r\n\t\t\r\n\t}\r\n\r\n}\r\n<\/pre>\n<p>Die Index-Action ist hier sehr rudiment\u00e4r, da sie alleine\u00a0keinerlei Funktionalit\u00e4t besitzt. Sie dient lediglich zur Anzeige der Hauptseite unserer Applikation:<\/p>\n<pre class=\"lang:php decode:true \">public function index()\r\n{\r\n\t\/\/ load view\r\n\t$this-&gt;load-&gt;view('home');\r\n}<\/pre>\n<p>Kommen wir nun zum HTML-Layout der verlinkten 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\" xmlns=\"http:\/\/www.w3.org\/1999\/html\"&gt;\r\n&lt;head&gt;\r\n    &lt;meta charset=\"utf-8\"&gt;\r\n    &lt;meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"&gt;\r\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\r\n    &lt;meta name=\"description\" content=\"\"&gt;\r\n    &lt;meta name=\"author\" content=\"\"&gt;\r\n\r\n    &lt;title&gt;CI Download-Speed&lt;\/title&gt;\r\n\r\n    &lt;!-- Latest compiled and minified CSS --&gt;\r\n    &lt;link rel=\"stylesheet\" href=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.7\/css\/bootstrap.min.css\"\r\n          integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz\/K68vbdEjh4u\" crossorigin=\"anonymous\"&gt;\r\n\r\n    &lt;!-- Custom CSS for basic styling --&gt;\r\n    &lt;link rel=\"stylesheet\" href=\"&lt;?php echo base_url(); ?&gt;assets\/css\/style.css\"\/&gt;\r\n\r\n    &lt;!-- Optional CSS for individual theming (powered by Bootswatch - https:\/\/bootswatch.com\/) --&gt;\r\n    &lt;link rel=\"stylesheet\" href=\"&lt;?php echo base_url(); ?&gt;assets\/css\/bootstrap_flatly.min.css\"\/&gt;\r\n\r\n    &lt;!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --&gt;\r\n    &lt;!--[if lt IE 9]&gt;\r\n    &lt;script src=\"https:\/\/oss.maxcdn.com\/html5shiv\/3.7.3\/html5shiv.min.js\"&gt;&lt;\/script&gt;\r\n    &lt;script src=\"https:\/\/oss.maxcdn.com\/respond\/1.4.2\/respond.min.js\"&gt;&lt;\/script&gt;\r\n    &lt;![endif]--&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n\r\n&lt;nav class=\"navbar navbar-default navbar-fixed-top\"&gt;\r\n    &lt;div class=\"container\"&gt;\r\n        &lt;div class=\"navbar-header\"&gt;\r\n            &lt;button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\" data-target=\"#navbar\"\r\n                    aria-expanded=\"false\" aria-controls=\"navbar\"&gt;\r\n                &lt;span class=\"sr-only\"&gt;Toggle navigation&lt;\/span&gt;\r\n                &lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n                &lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n                &lt;span class=\"icon-bar\"&gt;&lt;\/span&gt;\r\n            &lt;\/button&gt;\r\n            &lt;a class=\"navbar-brand\" href=\"#\"&gt;CodeIgniter Download-Speed&lt;\/a&gt;\r\n        &lt;\/div&gt;\r\n        &lt;div id=\"navbar\" class=\"collapse navbar-collapse\"&gt;\r\n            &lt;ul class=\"nav navbar-nav\"&gt;\r\n                &lt;li class=\"active\"&gt;&lt;a href=\"&lt;?php echo base_url(); ?&gt;\"&gt;Home&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=\"#about\"&gt;About&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=\"#contact\"&gt;Contact&lt;\/a&gt;&lt;\/li&gt;\r\n            &lt;\/ul&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/nav&gt;\r\n\r\n&lt;div class=\"container\"&gt;\r\n\r\n    &lt;div class=\"intro\"&gt;\r\n        &lt;h1&gt;Choose your download speed!&lt;\/h1&gt;\r\n        &lt;p class=\"lead\"&gt;\r\n            Lorem ipsum dolor sit amet, consetetur sadipscing elitr, &lt;br\/&gt;\r\n            sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, &lt;br\/&gt;\r\n            sed diam voluptua.\r\n        &lt;\/p&gt;\r\n\r\n        Here will be our core application...\r\n        \r\n\r\n\r\n    &lt;\/div&gt;\r\n    \r\n&lt;\/div&gt;\r\n\r\n\r\n&lt;!-- Bootstrap core JavaScript\r\n================================================== --&gt;\r\n&lt;!-- Placed at the end of the document so the pages load faster --&gt;\r\n&lt;script type=\"text\/javascript\" src=\"https:\/\/code.jquery.com\/jquery-3.2.1.min.js\"\r\n        integrity=\"sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n&lt;script type=\"text\/javascript\" src=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.7\/js\/bootstrap.min.js\"\r\n        integrity=\"sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa\"\r\n        crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n&lt;script type=\"text\/javascript\" src=\"&lt;?php echo base_url(); ?&gt;assets\/js\/app.js\"&gt;&lt;\/script&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Wir haben hier also mal das Basis-Layout mit einer Navigationsleiste sowie einem einfachen Textblock mit einer \u00dcberschrift angelegt.<\/p>\n<p>Gleich darunter (wo aktuell noch &#8222;<em>Here will be&#8230;<\/em>&#8220; steht) folgt nun das Markup unserer Anwendung: ein Speedmeter, das\u00a0wir auf Basis von &#8222;<a href=\"http:\/\/www.knowstack.com\/html5-canvas-speedometer\/\" target=\"_blank\" rel=\"noopener\">HTML5 Canvas Speedometer<\/a>&#8220; aufbauen werden. Dazu gibt&#8217;s zwei Download-Buttons (einen f\u00fcr eine kleinere, und einen zweiten f\u00fcr eine gr\u00f6\u00dfere Datei):<\/p>\n<pre class=\"lang:php decode:true\">&lt;canvas class=\"canvas\" id=\"myCanvas\" width=\"600\" height=\"400\"&gt;\r\n    Your browser does not support the HTML5 canvas tag.\r\n&lt;\/canvas&gt;\r\n\r\n&lt;div class=\"row\"&gt;\r\n    &lt;div class=\"col-md-6 col-md-offset-3\"&gt;\r\n        &lt;div id=\"slider\"&gt;\r\n            &lt;p class=\"lead\"&gt;max. &lt;span id=\"selectedSpeed\"&gt;&lt;\/span&gt; kB\/s&lt;\/p&gt;\r\n\r\n            &lt;input style=\"width:100%\" id=\"slide\" type=\"range\" min=\"0\" max=\"1750\" step=\"50\" value=\"100\"\/&gt;\r\n\r\n        &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/div&gt;\r\n\r\n\r\n&lt;p&gt;&amp;nbsp;&lt;\/p&gt;\r\n\r\n&lt;p&gt;\r\n    &lt;a href=\"#\" class=\"btn btn-primary btn-lg start-download\"\r\n       data-url=\"&lt;?php echo base_url(); ?&gt;home\/download\/1\/###speed###\"&gt;\r\n        &lt;span class=\"glyphicon glyphicon-download-alt\" aria-hidden=\"true\"&gt;&lt;\/span&gt; Download (100 MB)\r\n    &lt;\/a&gt;\r\n\r\n    &amp;nbsp;\r\n\r\n    &lt;a href=\"#\" class=\"btn btn-primary btn-lg start-download\"\r\n       data-url=\"&lt;?php echo base_url(); ?&gt;home\/download\/2\/###speed###\"&gt;\r\n        &lt;span class=\"glyphicon glyphicon-download-alt\" aria-hidden=\"true\"&gt;&lt;\/span&gt; Download (1 GB)\r\n    &lt;\/a&gt;\r\n&lt;\/p&gt;<\/pre>\n<p>Beim verlinkten <strong>bootstrap_flatly.min.css<\/strong> handelt es sich um das kostenlose Bootstrap-Theme &#8222;<a href=\"https:\/\/bootswatch.com\/flatly\/\">Flatly<\/a>&#8220; von <a href=\"https:\/\/bootswatch.com\/\">Bootswatch<\/a>.<br \/>\nDieses CSS-Theme ist optional und kann daher also gerne auch weggelassen werden.<\/p>\n<p>In der<strong> style.css<\/strong> definieren wir ein paar Basis-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}<\/pre>\n<p>In die verlinkte <strong>app.js<\/strong> kommt die eigentliche Logik f\u00fcr das Frontend unserer Applikation hinein.<\/p>\n<pre class=\"lang:js decode:true \">\/\/ Based on:  http:\/\/www.knowstack.com\/html5-canvas-speedometer\/\r\n\r\n$(document).ready(function(){\r\n\r\n    var draw = function(speed)\r\n    {\r\n        var  canvas = document.getElementById(\"myCanvas\");\r\n        var  context = canvas.getContext(\"2d\");\r\n        context.clearRect(0,0,canvas.width, canvas.height);\r\n        var centerX = canvas.width \/ 2;\r\n        var centerY = (canvas.height \/ 5) * 4;\r\n        var radius = canvas.width \/ 2 - 20;\r\n\r\n        context.beginPath();\r\n        context.arc(centerX, centerY, radius, Math.PI*0.10, Math.PI*-1.1, true);\r\n\r\n        var gradience = context.createRadialGradient(centerX, centerY, radius-radius\/2, centerX, centerY, radius-radius\/8);\r\n        gradience.addColorStop(0, '#ffffff');\r\n        gradience.addColorStop(1, '#18bc9c');\r\n\r\n        context.fillStyle = gradience;\r\n        context.fill();\r\n        context.closePath();\r\n        context.restore();\r\n\r\n        context.beginPath();\r\n        context.strokeStyle = '#ffffff';\r\n        context.translate(centerX,centerY);\r\n        var increment = 50;\r\n        context.font=\"15px Helvetica\";\r\n        for (var i=-18; i&lt;=18; i++)\r\n        {\r\n            angle = Math.PI\/30*i;\r\n            sineAngle = Math.sin(angle);\r\n            cosAngle = -Math.cos(angle);\r\n\r\n            if (i % 5 == 0) {\r\n                context.lineWidth = 8;\r\n                iPointX = sineAngle *(radius -radius\/4);\r\n                iPointY = cosAngle *(radius -radius\/4);\r\n                oPointX = sineAngle *(radius -radius\/7);\r\n                oPointY = cosAngle *(radius -radius\/7);\r\n\r\n                wPointX = sineAngle *(radius -radius\/2.5);\r\n                wPointY = cosAngle *(radius -radius\/2.5);\r\n                context.fillText((i+18)*increment,wPointX-2,wPointY+4);\r\n            }\r\n            else\r\n            {\r\n                context.lineWidth = 2;\r\n                iPointX = sineAngle *(radius -radius\/5.5);\r\n                iPointY = cosAngle *(radius -radius\/5.5);\r\n                oPointX = sineAngle *(radius -radius\/7);\r\n                oPointY = cosAngle *(radius -radius\/7);\r\n            }\r\n            context.beginPath();\r\n            context.moveTo(iPointX,iPointY);\r\n            context.lineTo(oPointX,oPointY);\r\n            context.stroke();\r\n            context.closePath();\r\n\r\n        }\r\n\r\n        var numOfSegments = speed\/increment;\r\n        numOfSegments = numOfSegments -18;\r\n        angle = Math.PI\/30*numOfSegments;\r\n        sineAngle = Math.sin(angle);\r\n        cosAngle = -Math.cos(angle);\r\n        pointX = sineAngle *(3\/4*radius);\r\n        pointY = cosAngle *(3\/4*radius);\r\n\r\n        context.beginPath();\r\n        context.strokeStyle = '#2c3e50';\r\n        context.arc(0, 0, 19, 0, 2*Math.PI, true);\r\n        context.fill();\r\n        context.closePath();\r\n\r\n        context.beginPath();\r\n        context.lineWidth=6;\r\n\r\n        context.moveTo(0,0);\r\n        context.lineTo(pointX,pointY);\r\n\r\n        context.stroke();\r\n        context.closePath();\r\n        context.restore();\r\n        context.translate(-centerX,-centerY);\r\n    };\r\n\r\n    \r\n    \/\/ TODO: add listener for range-field and function for setting the selected speed\r\n\r\n});<\/pre>\n<p>Damit w\u00e4re das grafische Canvas-Rendering des Speedmeters erledigt. Nun erweitern wir diese Datei um unsere eigentlichen Funktionen (Wichtig: unbedingt innerhalb des &#8222;document.ready()&#8220;-Blocks, dort wo aktuell noch &#8222;<em>TODO: add listener&#8230;<\/em>&#8220; steht, schreiben!). Dort befindet sich u.a.\u00a0die zentrale Funktion zum Setzen des ausgew\u00e4hlten Download-Speeds (&#8222;<em>setSpeed()<\/em>&#8222;)\u00a0und eines Listeners, der auf das Range-Eingabefeld reagiert. In weiterer Folge \u00fcbertr\u00e4gt der Listener den ausgew\u00e4hlten Wert ins Speedmeter, und passt\u00a0unsere beiden Download-Links dynamisch an.<\/p>\n<pre class=\"lang:js decode:true\">var setSpeed = function(speed)\r\n{\r\n    \/\/ prevent a speed of zero\r\n    if( speed == 0 ){\r\n        speed = 1;\r\n    }\r\n\r\n    \/\/ draw speedmeter graphic\r\n    draw(speed);\r\n\r\n    \/\/ write text under speedmeter graphic\r\n    $('#selectedSpeed').text(speed);\r\n\r\n    \/\/ set individual download url with dynamically speed assignment\r\n    $('a.start-download').each(function(i, v){\r\n        var url = $(v).data('url');\r\n        url = url.replace('###speed###', speed);\r\n\r\n        $(v).attr('href', url);\r\n    });\r\n};\r\n\r\n\r\n\/\/ set inital speed\r\nsetSpeed(100);\r\n\r\n\r\n\/\/ check for change of speed value while dragging\r\n$(document).on('input change', '#slide', function() {\r\n    setSpeed( $(this).val() );\r\n});<\/pre>\n<p>Weil der Listener die beiden Download-Links dynamisch anpasst, haben wir vorhin das Linkziel der beiden Download-Buttons nicht direkt, sondern nur \u00fcber ein <a href=\"http:\/\/api.jquery.com\/data\/\" target=\"_blank\" rel=\"noopener\">data<\/a>-Attribut mittels einem Platzhalter f\u00fcr den eigentlichen Speed gesetzt. So k\u00f6nnen wir dieses Attribut als Vorlage nutzen, und das Linkziel immer wieder dynamisch neu setzen. Initial setzen wir den Download-Speed auf 100 KB\/s. Dies ist die Standardeinstellung, die der Benutzer bekommt, wenn er unsere Applikation \u00f6ffnet.<\/p>\n<p>&nbsp;<\/p>\n<h2>Schritt 3: Drosselung einbauen<\/h2>\n<p>F\u00fcr den Einbau der Speed-Drosselung ben\u00f6tigen wir nun unsere Download-Action, deren Struktur wir zuvor angelegt haben.<\/p>\n<pre class=\"lang:php decode:true \">public function download($type = 1, $speed_kbs = 64)\r\n{\r\n\t\/\/ detect, which example file should be used\r\n\tif ($type == 2) {\r\n\t\t$filename = '1000mb.bin';\r\n\t} else {\r\n\t\t$filename = '100mb.bin';\r\n\t}\r\n\r\n\t\/\/ build up public URL for file (for public access via cURL)\r\n\t$public_filename = base_url() . 'downloads\/' . $filename;\r\n\r\n\t\/\/ build up internal URL for file (for internal access, like filesize())\r\n\t$local_filename = FCPATH . 'downloads\/' . $filename;\r\n\r\n\r\n\t\/\/ get speed in Bytes\/s\r\n\t$speed = $speed_kbs * 1000;\r\n\r\n\t\/\/ prepare headers for forcing file download\r\n\theader('Content-Type: application\/octet-stream');\r\n\theader('Content-Length: ' . filesize($local_filename));\r\n\theader('Content-Disposition: attachment; filename=\"' . basename($filename) . '\"');\r\n\r\n\r\n\t\/\/ TODO: get file and provide it as streamed download (with speed limitation)\r\n}<\/pre>\n<p>In dieser wird (in unserem Beispiel) zun\u00e4chst \u00fcberpr\u00fcft, ob die gro\u00dfe oder die kleine Beispiel-Datei geladen werden soll. Sobald dies geschehen ist, bauen wir uns die \u00f6ffentliche URL (mit Domain oder IP, je nach Konfiguration) und die interne URL (absoluter Pfad am Server) zusammen. Gleichzeitig berechnen wir uns unseren Download-Speed, indem wir die \u00fcbergebenen KB\/s in Bytes\/s umrechnen (mit dem Faktor 1000).<\/p>\n<p>Anschlie\u00dfend definieren wir uns die PHP-Header f\u00fcr einen Dateidownload. Dazu verwenden wir als &#8222;Content-Type&#8220; einfach &#8222;<em>application\/octet-stream<\/em>&#8222;, sodass der Download immer erzwungen wird, und der Browser nicht versucht, die Datei selbst zu \u00f6ffnen bzw. anzuzeigen. Des Weiteren folgen nun (optionale) Angaben zur Dateigr\u00f6\u00dfe, damit der Browser den Fortschritt des laufenden Downloads kennt und anzeigen kann. Am Ende kommt noch der Dateiname selbst dazu.<\/p>\n<p>Nun folgt der eigentliche Download. Daf\u00fcr nutzen wir cURL und setzen hier dessen Parameter wie folgt:<\/p>\n<pre class=\"lang:php decode:true \">\/\/ init cURL\r\n$ch = curl_init();\r\n\r\n\/\/ read file from public URL\r\ncurl_setopt($ch, CURLOPT_URL, $public_filename);\r\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\r\ncurl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 500);\r\n\r\n\/\/ limit download speed (in bytes per second)\r\ncurl_setopt($ch, CURLOPT_MAX_RECV_SPEED_LARGE, $speed);\r\n\r\n\/\/ stream data in realtime, instead of locally download before finally delivery\r\ncurl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($curl, $data) {\r\n\techo $data;\r\n\treturn strlen($data);\r\n});\r\n\r\n\/\/ perform \"cURL-query\"\r\ncurl_exec($ch);\r\n\r\n\/\/ close cURL session\r\ncurl_close($ch);<\/pre>\n<p>Im Grunde handelt es sich hier gro\u00dfteils um Standard-Parameter, bis auf zwei Ausnahmen: <a href=\"https:\/\/curl.haxx.se\/libcurl\/c\/CURLOPT_MAX_RECV_SPEED_LARGE.html\" target=\"_blank\" rel=\"noopener\"><strong>CURLOPT_MAX_RECV_SPEED_LARGE<\/strong><\/a> und <a href=\"https:\/\/curl.haxx.se\/libcurl\/c\/CURLOPT_WRITEFUNCTION.html\" target=\"_blank\" rel=\"noopener\"><strong>CURLOPT_WRITEFUNCTION<\/strong><\/a>.<\/p>\n<p>Die Option <strong>CURLOPT_MAX_RECV_SPEED_LARGE<\/strong> erm\u00f6glicht es uns, den maximalen Download-Speed festzulegen, mit welchem die cURL-Bibliothek die Daten liest. Die Angabe hier erfolgt in Bytes\/s, daher unsere vorherige Umrechnung. Wird hier der Wert &#8222;0&#8220; angegeben, erfolgt keine Drosselung, und der Download wird mit unbegrenzter Geschwindigkeit durchgf\u00fchrt. Die tats\u00e4chliche Geschwindigkeit ist dann nur mehr abh\u00e4ngig von den externen Faktionen, wie z.B. Internetanbindung selbst.<\/p>\n<p>Damit die von cURL gelesenen Daten auch unmittelbar an den Benutzer gestreamt, und nicht minutenlang (oder gar Stunden! &#8211; je nach Speed) zuerst lokal auf den Server geladen wird , ehe sie ausgeliefert werden, geben wir mit Hife von <strong>CURLOPT_WRITEFUNCTION<\/strong> unseren eigenen Output-Handler an. Dieser sorgt daf\u00fcr, dass der empfangene Inhalt 1:1 und in Echtzeit an den Benutzer weitergeleitet wird.<\/p>\n<p>Zusammengefasst sieht unsere Download-Action nun also wie folgt aus:<\/p>\n<pre class=\"lang:php decode:true \">public function download($type = 1, $speed_kbs = 64)\r\n{\r\n\t\/\/ detect, which example file should be used\r\n\tif ($type == 2) {\r\n\t\t$filename = '1000mb.bin';\r\n\t} else {\r\n\t\t$filename = '100mb.bin';\r\n\t}\r\n\r\n\t\/\/ build up public URL for file (for public access via cURL)\r\n\t$public_filename = base_url() . 'downloads\/' . $filename;\r\n\r\n\t\/\/ build up internal URL for file (for internal access, like filesize())\r\n\t$local_filename = FCPATH . 'downloads\/' . $filename;\r\n\r\n\r\n\t\/\/ get speed in KB\/s\r\n\t$speed = $speed_kbs * 1000;\r\n\r\n\t\/\/ prepare headers for forcing file download\r\n\theader('Content-Type: application\/octet-stream');\r\n\theader('Content-Length: ' . filesize($local_filename));\r\n\theader('Content-Disposition: attachment; filename=\"' . basename($filename) . '\"');\r\n\r\n\r\n\t\/\/ init cURL\r\n\t$ch = curl_init();\r\n\r\n\t\/\/ read file from public URL\r\n\tcurl_setopt($ch, CURLOPT_URL, $public_filename);\r\n\tcurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\r\n\tcurl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 500);\r\n\r\n\t\/\/ limit download speed (in bytes per second)\r\n\tcurl_setopt($ch, CURLOPT_MAX_RECV_SPEED_LARGE, $speed);\r\n\r\n\t\/\/ stream data in realtime, instead of locally download before finally delivery\r\n\tcurl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($curl, $data) {\r\n\t\techo $data;\r\n\t\treturn strlen($data);\r\n\t});\r\n\r\n\t\/\/ perform \"cURL-query\"\r\n\tcurl_exec($ch);\r\n\r\n\t\/\/ close cURL session\r\n\tcurl_close($ch);\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h2>Fazit<\/h2>\n<p>Eine Speed-Drosselung f\u00fcr Dateidownloads l\u00e4sst sich mit Hilfe der cURL-Bibliothek sehr leicht und schnell realisieren. Es bedarf hier lediglich der korrekten Konfiguration von cURL.<\/p>\n<p>Aktuell w\u00e4ren in unserem Beispiel-Projekt w\u00e4re der Zugriff aud die Downloads auch direkt \u00fcber deren \u00f6ffentliche URL m\u00f6glich. Dies ist f\u00fcr den internen Download via cURL notwendig, da cURL hier mehr oder weniger nur als Proxy fungiert. In der Praxis sollte die direkte Zugriffsm\u00f6glichkeit jedoch unterbunden werden. Unter der Annahme, dass der Server eine statische IP-Adresse besitzt, kann man z.B. in den &#8222;<em>downloads<\/em>&#8222;-Ordner eine .htaccess legen, die\u00a0den Zugriff nur \u00fcber die Server-IP zul\u00e4sst (alternativ auch \u00fcber die vHost-Config).<\/p>\n<p>Hier ein Beispiel f\u00fcr eine solche .htaccess-Datei (188.65.77.77 w\u00e4re hier die Server-IP, auf welchem die Applikation l\u00e4uft):<\/p>\n<pre class=\"lang:default decode:true \">Deny from all\r\nAllow from 188.65.77.77<\/pre>\n<p>Somit w\u00e4re gew\u00e4hrleistet, dass die Applikation zum Zwecke des internen Downloads auf die \u00f6ffentliche URL zugreifen darf, alle anderen Benutzer jedoch nicht. Auch w\u00e4re m\u00f6glich, dass die Dateien von einem Remote-Server geladen werden und die Meta-Information (wie z.B. Dateigr\u00f6\u00dfe) aus einer Datenbank bezogen wird.<\/p>\n<p>Die beiden verlinkten Dummy-Download-Dateien k\u00f6nnen u.a. \u00fcber die <a href=\"https:\/\/anexia.com\/map\/\" target=\"_blank\" rel=\"noopener\">Anexia Network Map <\/a>oder alternativ direkt \u00fcber diese Links bezogen werden: <a href=\"http:\/\/37.252.235.199\/100mb.bin\" target=\"_blank\" rel=\"noopener\">100MB<\/a> und <a href=\"http:\/\/37.252.235.199\/1000mb.bin\" target=\"_blank\" rel=\"noopener\">1GB<\/a> (via dem\u00a0<a href=\"http:\/\/www.datasix.at\/\" target=\"_blank\" rel=\"noopener\">DATASIX<\/a>-Rechenzentrum).<\/p>\n<p>In diesem Tutorial haben wir mit dem\u00a0CodeIgniter-Framework gearbeitet, weil es\u00a0sehr leicht verst\u00e4ndlich ist und auch fast keine Einarbeitungszeit erfordert. Im Prinzip kann hierf\u00fcr aber jedes beliebige Framework eignesetzt werden, wie z.B. auch <a href=\"https:\/\/laravel.com\/\" target=\"_blank\" rel=\"noopener\">Laravel <\/a>oder <a href=\"https:\/\/framework.zend.com\/\" target=\"_blank\" rel=\"noopener\">Zend<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In diesem Tutorial zeige ich, wie man eine Option in ein CodeIgniter-Projekt integriert, um den Download-Speed drosseln zu k\u00f6nnen.<\/p>\n","protected":false},"author":15,"featured_media":2961,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[78,411,412,414,415,14,413,77],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Mit CodeIgniter und cURL den Download-Speed drosseln - ANEXIA Blog<\/title>\n<meta name=\"description\" content=\"In diesem Tutorial zeige ich, wie man eine Option in ein CodeIgniter-Projekt integriert, um den Download-Speed drosseln zu k\u00f6nnen.\" \/>\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\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Mit CodeIgniter und cURL den Download-Speed drosseln - ANEXIA Blog\" \/>\n<meta property=\"og:description\" content=\"In diesem Tutorial zeige ich, wie man eine Option in ein CodeIgniter-Projekt integriert, um den Download-Speed drosseln zu k\u00f6nnen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/\" \/>\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-09-21T14:39:34+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-04-19T07:11:22+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"672\" \/>\n\t<meta property=\"og:image:height\" content=\"372\" \/>\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=\"14\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/\",\"url\":\"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/\",\"name\":\"Mit CodeIgniter und cURL den Download-Speed drosseln - ANEXIA Blog\",\"isPartOf\":{\"@id\":\"https:\/\/anexia.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"datePublished\":\"2017-09-21T14:39:34+00:00\",\"dateModified\":\"2022-04-19T07:11:22+00:00\",\"author\":{\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de\"},\"description\":\"In diesem Tutorial zeige ich, wie man eine Option in ein CodeIgniter-Projekt integriert, um den Download-Speed drosseln zu k\u00f6nnen.\",\"breadcrumb\":{\"@id\":\"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#primaryimage\",\"url\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"contentUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"width\":672,\"height\":372},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/anexia.com\/blog\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Mit CodeIgniter und cURL den Download-Speed drosseln\"}]},{\"@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":"Mit CodeIgniter und cURL den Download-Speed drosseln - ANEXIA Blog","description":"In diesem Tutorial zeige ich, wie man eine Option in ein CodeIgniter-Projekt integriert, um den Download-Speed drosseln zu k\u00f6nnen.","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\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/","og_locale":"de_DE","og_type":"article","og_title":"Mit CodeIgniter und cURL den Download-Speed drosseln - ANEXIA Blog","og_description":"In diesem Tutorial zeige ich, wie man eine Option in ein CodeIgniter-Projekt integriert, um den Download-Speed drosseln zu k\u00f6nnen.","og_url":"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/","og_site_name":"ANEXIA Blog","article_publisher":"https:\/\/www.facebook.com\/anexiagmbh\/","article_published_time":"2017-09-21T14:39:34+00:00","article_modified_time":"2022-04-19T07:11:22+00:00","og_image":[{"width":672,"height":372,"url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.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":"14\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/","url":"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/","name":"Mit CodeIgniter und cURL den Download-Speed drosseln - ANEXIA Blog","isPartOf":{"@id":"https:\/\/anexia.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#primaryimage"},"image":{"@id":"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#primaryimage"},"thumbnailUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","datePublished":"2017-09-21T14:39:34+00:00","dateModified":"2022-04-19T07:11:22+00:00","author":{"@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de"},"description":"In diesem Tutorial zeige ich, wie man eine Option in ein CodeIgniter-Projekt integriert, um den Download-Speed drosseln zu k\u00f6nnen.","breadcrumb":{"@id":"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#primaryimage","url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","contentUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","width":672,"height":372},{"@type":"BreadcrumbList","@id":"https:\/\/anexia.com\/blog\/de\/mit-codeigniter-und-curl-den-download-speed-drosseln\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/anexia.com\/blog\/de\/"},{"@type":"ListItem","position":2,"name":"Mit CodeIgniter und cURL den Download-Speed drosseln"}]},{"@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":"de","translations":{"de":2939,"en":6767},"amp_enabled":true,"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/2939"}],"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=2939"}],"version-history":[{"count":25,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/2939\/revisions"}],"predecessor-version":[{"id":6769,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/2939\/revisions\/6769"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media\/2961"}],"wp:attachment":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media?parent=2939"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/categories?post=2939"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/tags?post=2939"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}