{"id":7045,"date":"2010-04-28T18:01:56","date_gmt":"2010-04-28T16:01:56","guid":{"rendered":"http:\/\/blog.isnochys.de\/?p=7045"},"modified":"2010-04-28T15:49:08","modified_gmt":"2010-04-28T13:49:08","slug":"url-shortener-quick-dirty","status":"publish","type":"post","link":"https:\/\/blog.isnochys.de\/?p=7045","title":{"rendered":"URL Shortener &#8211; Quick &#038; Dirty"},"content":{"rendered":"<p><a href=\"http:\/\/wuerzblog.de\/2010\/04\/26\/von-url4-eu-ueber-scientology-zu-charivari\/\">Radio Charivari <\/a>nutzt es nicht.<br \/>\nAndere setzen <a href=\"http:\/\/ow.ly\/\">aufs Framejacking<\/a>.<br \/>\n<em>Aber es kann doch nicht so schwer sein, einen eigenen URL Verk\u00c3\u00bcrzer zu basteln?<\/em><\/p>\n<p>Ist es ja auch nicht.<br \/>\nIn der Quick&#038;Dirty Reihe gibts von mir heute einen Verk\u00c3\u00bcrzer.<br \/>\n<em>Was brauchen wir dazu?<\/em><\/p>\n<ul>\n<li>Webserver, Apache<\/li>\n<li>Perl<\/li>\n<li>Domaine<\/li>\n<\/ul>\n<p>Ok, die Domaine ist klar, irgendwas Kurzes.<br \/>\nAls Ziel hab ich mir gesetzt, den schmutzigsten und rudiment\u00c3\u00a4rsten Shortener zu skripten, den man sich vorstellen kann.<br \/>\n<em>Sicherheitsfeatures?<\/em><br \/>\nN\u00c3\u00b6, wozu auch, kostet nur Codezeilen:))<br \/>\n<em>Datenbank?<\/em><br \/>\nMit so Extras geben wir uns nicht ab, eine Datei tuts auch.<\/p>\n<p>St\u00c3\u00bcrzen wir uns also gleich ins Geschehen..<br \/>\n<code><br \/>\n#!\/usr\/bin\/perl<br \/>\n<\/code><br \/>\nGenauso muss ein gutes Skript anfangen.<br \/>\n<code><br \/>\nuse strict;<br \/>\nuse CGI;<br \/>\n<\/code><br \/>\n<em>Wow, doch ein Package? Du hast doch gesagt, wir machen was ganz Rudiment\u00c3\u00a4res?<\/em><br \/>\nJa, das machen wir auch. Aber mir erleichtert das Skript die Interaktion. Und au\u00c3\u0178erdem hab ich keinen Rechner gefunden, auf dem das Packet nicht installiert w\u00c3\u00a4re.<br \/>\nIst auch das Einzige..versprochen!<br \/>\n<code><br \/>\nmy %database;<br \/>\nmy %revdatabase;<br \/>\nmy $save = \"c:\\\\tmp\\\\url\";<br \/>\nmy $cgi = CGI->new;<br \/>\n<\/code><br \/>\n2 Hashes aufsetzen, die Datei festlegen, in der wir unsere URLs reinschreiben, und ein Webobjekt erstellen.<br \/>\n<code><br \/>\n%database=get_file_database($save);<br \/>\n<\/code><br \/>\nDenn wollen wir mal unsere Datenbank auch in den Hash ablegen:<br \/>\n<code><br \/>\nsub get_file_database{<br \/>\n\tmy $file = shift;<br \/>\n\topen(FILE,\"< $file\");\n\tmy %datbase=();\n\twhile(FILE){\n\t\tif($_=~ \/^(\\d+)\\s+(.+)\/){\n\t\t\t$datbase{$1}=$2;\n        }}\n\tclose(FILE);\n\treturn %datbase;}\n<\/code><br \/>\nNa, wie haben wir unsere URL Datei aufgebaut?<br \/>\nRichtig: \"Index Leerzeichen URL\"<br \/>\nWer jetzt zu weinen beginnt, hat einfach keine starken Nerven.<br \/>\nWeiter im Hauptcode.<br \/>\n<em>Hier beginnt nun eine if-Klausel.<\/em><br \/>\nDie ich von hinten aufz\u00c3\u00a4umen m\u00c3\u00b6chte:<br \/>\n<\/code><code><br \/>\n}else{<br \/>\n\tprint $cgi->start_html(-title=>'My Urlizer');<br \/>\n\tprint $cgi->header('text\/html'), $cgi->h1('Enter URL to shorten');<br \/>\n\tformular($cgi);<br \/>\n\tprint $cgi->end_html;<br \/>\n}<br \/>\n<\/code><br \/>\nIst recht simpel, Titel wird gesetzt und ein Formular erstellt, dort kann man die URL eintragen.<br \/>\nHab ich von Selfhtml kopiert, ist somit nicht weiter lustig.<br \/>\nJetzt aber zur\u00c3\u00bcck zur Bedingung. Hier steht noch einiges aus.<br \/>\n<code><br \/>\nif($cgi->param('absenden')){<br \/>\n<\/code><br \/>\nAh, aus dem Formularfeld wird absenden weitergegeben.<br \/>\nAlso vermutlich, wenn wir eine URL zum K\u00c3\u00bcrzen haben..<br \/>\nGenau:<br \/>\n<code><br \/>\n\tprint $cgi->header;<br \/>\n\tprint $cgi->start_html(-title=>'My Urlizer');<br \/>\n<\/code><br \/>\nZun\u00c3\u00a4chst der Header..*g\u00c3\u00a4hn*<br \/>\n<code><br \/>\n\tmy $idz = scalar keys %database;<br \/>\n\t$idz += 1;<br \/>\n\t%revdatabase= reverse %database;<br \/>\n<\/code><br \/>\nHa!<br \/>\ndie L\u00c3\u00a4nge unserer Datenbank plus 1 setzen..und die Datenbank umdrehen.<br \/>\nweshalb die Datenbank umdrehen?<br \/>\n<code><br \/>\n\tprint $cgi->h3('Your URL is');<br \/>\n\tif($revdatabase{$cgi->param('url')}){<br \/>\n<\/code><br \/>\neben deshalb. Ich will gucken, ob ich die URL schonmal gespeichert hab, dann muss ich das nicht nochmals aufnehmen.<br \/>\nUnd jetzt kommt der kontroverse Teil..<br \/>\n<code><br \/>\n\t\tprint $cgi->p(encode_36($revdatabase{$cgi->param('url')}));<br \/>\n\t\t# print $cgi->p($revdatabase{$cgi->param('url')});<br \/>\n\t}else{<br \/>\n              write_file_database($idz, $cgi->param('url'), $save);<br \/>\n\t\tprint $cgi->p(encode_36($idz));<br \/>\n\t\t# print $cgi->p($idz);<br \/>\n\t}<br \/>\n<\/code><br \/>\n<em>Du hast doch gesagt, das ding soll einfach sein!!1!einself<\/em><br \/>\nJa, ich gebs zu, aber ich hatte zu einem fr\u00c3\u00bchen Zeitpunkt schon mit der base36 encodierung begonnen. also, weshalb sollte ich das nicht nehmen?<br \/>\n\ud83d\ude42<br \/>\nUnd wer auf reiner Zahlenbasis arbeiten will, dann enth\u00c3\u00a4lt die verk\u00c3\u00bcrzte URL eben im  hinteren Teil nur Zahlen, der soll die kommentierten Zeilen auskommentieren und die dar\u00c3\u00bcber kommentieren.<br \/>\nZufrieden?<br \/>\n<code><br \/>\n\tprint $cgi->p('Short another URL?');<br \/>\n\tformular($cgi)<br \/>\n<\/code><br \/>\nUnd noch ans Ende das Formular geklebt, vielleicht will man noch ne URL k\u00c3\u00bcrzen.<br \/>\nJetzt aber kleiner Sprung zur Dateireinschreibefunktion:<br \/>\n<code><br \/>\nsub write_file_database{<br \/>\n\tmy $id = shift;<br \/>\n\tmy $url = shift;<br \/>\n\tmy $file = shift;<br \/>\n\topen(FILE,\">>$file\") or open(FILE,\">$file\");<br \/>\n\tprint FILE \"$id\\t$url\\n\";<br \/>\n\tclose(FILE);}<br \/>\n<\/code><br \/>\nWer vorhin noch nicht geweint hat, wird sp\u00c3\u00a4testens jetzt zusammenbrechen.<br \/>\nNicht nur schreiben wir in die Datei nur Zahl und URL rein.<br \/>\nNein, viel schlimmer.<br \/>\n<em>Wenn ich was an eine Datei nicht anh\u00c3\u00a4ngen kann.\u00c3\u00bcberschreib ich die Datei?<\/em><br \/>\nGenau, das ist Dirty.<br \/>\nSo erzeuge ich schnell, ohne Touch oder \u00c3\u00a4hnliches eine Datei.<br \/>\n:))<br \/>\n<em>Und vernichte sie im Ernstfall auch wieder.<\/em><br \/>\nGenau, deshalb sollte man auch keine URL shortener verwenden!<br \/>\n\ud83d\ude09<br \/>\nNoch dabei?<br \/>\nTaschent\u00c3\u00bccher vollgeweint?<br \/>\nDann scheut euch mal die base36 Funktionen an, zun\u00c3\u00a4chst aus einer Zahl, z.B. 100, eine Base36, z.B. 2S, Zeichenkette erstellen:<br \/>\n<code><br \/>\nsub encode_36{<br \/>\n  my $n = shift;<br \/>\n  my $s=\"\";<br \/>\n  return(0) if $n == 0;<br \/>\n  while ( $n ) {<br \/>\n\t\tmy $v = $n % 36;<br \/>\n\t\tif($v < = 9) {\n\t\t\t$s .= $v;\n\t\t} else {\n\t\t\t$s .= chr(ord(\"A\")  -10 + $v);\n\t\t}\n\t\t$n = int $n \/ 36;\n  }\n  return \"0\" x ( 0 - length($s)) . reverse($s);}\n<\/code><br \/>\nUnd nat\u00c3\u00bcrlich wieder r\u00c3\u00bcckwandeln, in eine Zahl:<br \/>\n<\/code><code><br \/>\nsub decode_36 {<br \/>\n\tmy ($t, $i)  = 0;<br \/>\n\tforeach(split \/\/, reverse uc shift) {<br \/>\n\t\t$_ = ord($_) - ord(\"A\") +10 unless \/\\d\/;<br \/>\n\t\t$t += $_ * (36 ** $i++);<br \/>\n\t}<br \/>\n\treturn $t;}<br \/>\n<\/code><br \/>\nOk, das ganze hab ich aus Math::Base36 geklaut.<br \/>\nUnd etwas modifiziert.<br \/>\nord(&#8222;A&#8220;) hinzugef\u00c3\u00bcgt..denn nicht auf jedem System ist &#8222;A&#8220; 65 im ASCII Code.<br \/>\nAber wie ich festgestellt habe, kann man nat\u00c3\u00bcrlich auch diesen Base36 Quatsch weglassen.<br \/>\nWerden die kurzen URLs eben nicht so fancy und sophisticated.<br \/>\n<em>Wars das schon?<\/em><br \/>\nNat\u00c3\u00bcrlich nicht, denn eine kurze URL muss bei Ankunft weitergeleitet werden:<br \/>\n<code><br \/>\n}elsif($cgi->param('red')){<br \/>\n\tredirect($cgi->param('red'))<br \/>\n<\/code><br \/>\nKurz und schmerzlos:<br \/>\n<code><br \/>\nsub redirect{<br \/>\n\tmy $short = shift;<br \/>\n\t$short = decode_36($short);#<br \/>\n\tmy $url = $database{$short};<br \/>\n\t$cgi->redirect($url);}<br \/>\n<\/code><br \/>\nBei einer reinen Zahlenshorturldienstleistung muss man nat\u00c3\u00bcrlich die 3. Zeile auskommentieren.<\/p>\n<p>Das w\u00c3\u00a4rs eigentlich gewesen fehlt nur noch die Apache Konfiguration:<br \/>\n<code><br \/>\nRewriteEngine On<br \/>\nRewriteBase \/<br \/>\nRewriteCond %{REQUEST_FILENAME} !-f<br \/>\nRewriteCond %{REQUEST_FILENAME} !-d<br \/>\nRewriteRule ^(.*)$ shoturl.pl?red=$1 [L]<br \/>\n<\/code><br \/>\nHab ich so ausm Netz und nicht \u00c3\u00bcberpr\u00c3\u00bcft.<br \/>\nWozu auch, klappt sicherlich schon.<\/p>\n<p>Wie Ihr seht, ist das Skript so Q&#038;D, dass ich nichtmal den Dateinamen shoturl.pl angepasst hab.<\/p>\n<p>Schm\u00c3\u00a4hungen, Drohbriefe und sonstige Sp\u00c3\u00a4\u00c3\u0178e k\u00c3\u00b6nnt ihr wie immer in den Kommentaren hinterlassen<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Radio Charivari nutzt es nicht. Andere setzen aufs Framejacking. Aber es kann doch nicht so schwer sein, einen eigenen URL Verk\u00c3\u00bcrzer zu basteln? Ist es ja auch nicht. In der Quick&#038;Dirty Reihe gibts von mir heute einen Verk\u00c3\u00bcrzer. Was brauchen &hellip; <a href=\"https:\/\/blog.isnochys.de\/?p=7045\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[2],"tags":[],"class_list":["post-7045","post","type-post","status-publish","format-standard","hentry","category-initializing-devchaos"],"_links":{"self":[{"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=\/wp\/v2\/posts\/7045","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7045"}],"version-history":[{"count":7,"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=\/wp\/v2\/posts\/7045\/revisions"}],"predecessor-version":[{"id":7052,"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=\/wp\/v2\/posts\/7045\/revisions\/7052"}],"wp:attachment":[{"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7045"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7045"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.isnochys.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7045"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}