<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <id>tag:www.ifconfig.se,2005:/feed</id>
  <link rel="alternate" type="text/html" href="http://www.ifconfig.se" />
  
  <title>www.ifconfig.se</title>
  <updated>2012-02-01T22:43:34+01:00</updated>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ifconfig-se" /><feedburner:info uri="ifconfig-se" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <id>http://www.ifconfig.se/vim-vimrc-konfiguration</id>
    <published>2011-04-19T21:42:00+02:00</published>
    <updated>2012-02-01T22:43:34+01:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/fLIKNU1fL98/vim-vimrc-konfiguration" />
    <title>Gör Vim ännu trevligare med ~/.vimrc</title>
    <content type="html">&lt;img class="right photo" src="/images/vim-logo.png" alt="Vim - Vi Improved" /&gt;
&lt;p&gt;Jag har använt &lt;a href="http://www.vim.org/" title="Vim - Vi Improved" rel="external nofollow" target="_blank"&gt;Vim&lt;/a&gt; som min primära text-editor de senaste 8-10 åren och skulle nog finna det väldigt svårt att byta till något annat. Trots detta så känner jag mig halvt handikappad då jag använder vanliga standard &lt;strong&gt;vi&lt;/strong&gt; i t.ex &lt;a href="http://www.freebsd.org/" title="The power to serve!" rel="nofollow external" target="_blank"&gt;FreeBSD&lt;/a&gt; eller &lt;a href="http://www.archlinux.org/" title="Arch Linux" rel="nofollow external" target="_blank"&gt;ArchLinux&lt;/a&gt;. Detta beror på att jag förväntar mig att saker som att kunna flytta markören med piltangenterna inte fungerar i &lt;em&gt;insert&lt;/em&gt;-mode utan diverse ändringar i min &lt;strong&gt;~/.vimrc&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Många finner det svårt att förstå hur folk kan använda &lt;em&gt;Vim&lt;/em&gt; då de är vana att kunna markera, klippa ut och flytta markören med mus-pekaren pga editorer så som notepad och Word. Faktum är att du blir betydligt mer produktiv om du tar som vana att endast använda tangentbordet.&lt;/p&gt;

&lt;p&gt;Jag föredrar att &lt;strong&gt;vim&lt;/strong&gt; har diverse simpla funktioner som syntax highlighting, att &lt;em&gt;vim&lt;/em&gt; kommer ihåg vart i filen jag senast var, automatiskt intenderar kod (&lt;em&gt;tips: &lt;strong&gt;:set paste&lt;/strong&gt;&lt;/em&gt;), att &lt;em&gt;vim&lt;/em&gt; konverterar text från ISO till UTF-8 on-the-fly, osv. För att få detta beteende, spara min &lt;a href="/.vimrc"&gt;~/.vimrc&lt;/a&gt; och lägg den i din hemma-mapp.&lt;/p&gt;

&lt;pre class="brush: plain"&gt;" #####
" #
" # File:   /usr/local/share/vim/vimrc, $HOME/.vimrc
" # Author: Jesper Wallin (jesper@ifconfig.se)
" # Date:   22-09-2011
" #

" ###################
" # VIM default
" ###################
set nocompatible

" ###################
" # Fix backspace
" ###################
set bs=2

" ###################
" # Auto-indenting
" ###################
set ai

" ###################
" # Hilight searches
" ###################
set hlsearch

" ###################
" # Use .viminfo
" ###################
set viminfo='20,\"500

" ###################
" # Command history
" ###################
set history=50

" ###################
" # Show cursor
" ###################
set ruler

" ###################
" # Disable modeline
" ###################
set nomodeline

" ###################
" # Encode UTF-8
" ###################
if v:lang =~ "utf8$" || v:lang =~ "UTF-8$"
  set fileencodings=utf-8,latin1
endif

" ###################
" # Don't use Ex mode, use Q for formatting
" ###################
map Q gq

" ###################
" # Syntax Highlighting
" ###################
syntax on

" ###################
" # Tweaks for xterm
" ###################
if &amp;term=="xterm"
  set t_RV=          " don't check terminal version
  set t_Co=8
  set t_Sb=^[4%dm
  set t_Sf=^[3%dm
endif

" ###################
" # Move to last position
" ###################
au BufReadPost * if line("'\"") &gt; 0 &amp;&amp; line("'\"") &lt;= line("$") |
                         \ exe "normal g'\"" | endif

" ###################
" # Remove trailing whitespaces on PHP files.
" ###################
autocmd BufWritePre *.php :%s/\s\+$//e&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Uppdatering:&lt;/strong&gt; Har lagt till highlight på sök samt att den tar bort mellanslag i slutet på alla rader i PHP-filer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;För att få denna konfiguration att fungera system-wide, döp om filen till &lt;em&gt;vimrc&lt;/em&gt;, utan punkten innan. Därefter flyttar du filen till &lt;em&gt;/etc&lt;/em&gt; (se &lt;em&gt;man vim&lt;/em&gt; för mer information om detta)&lt;/p&gt;

&lt;p&gt;Kommentera gärna och berätta vilken editor som är din favorit och varför. Om det råkar vara vim, vad för konfiguration använder du? :-)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/fLIKNU1fL98" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/vim-vimrc-konfiguration</feedburner:origLink></entry>
  <entry>
    <id>http://www.ifconfig.se/php-curl-parallellt</id>
    <published>2011-01-03T08:05:00+01:00</published>
    <updated>2011-11-30T00:17:39+01:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/T8xmMbqUwjQ/php-curl-parallellt" />
    <title>Hämta filer parallellt med PHP och libcurl</title>
    <content type="html">&lt;h2&gt;Varför hämta filer &lt;em&gt;parallellt&lt;/em&gt;?&lt;/h2&gt;
&lt;p&gt;I normala fall när du surfar runt på webben så hanterar webbläsaren alla nerladdningar. Alla moderna webbläsare hämtar de filer (&lt;abbr title="Cascading StyleSheet"&gt;CSS&lt;/abbr&gt;, JavaScript, osv) som finns på en webbplats parallellt. Dvs, alla filer hämtas samtidigt istället för att nerladdningarna ska behöva vänta på varandra innan de kan börja.&lt;/p&gt;

&lt;p&gt;Låt säga att du hämtar information från andra webbplatser för att lagra och sedan presentera den på din egna webbplats. Ett exempel kan vara affiliatenätverk, som ofta erbjuder information om produkter via &lt;abbr title="Extensible Markup Language"&gt;XML&lt;/abbr&gt;-filer. Här kan det vara trevligt att hämta all data parallellt för att snabba upp processen.&lt;/p&gt;

&lt;p&gt;Ett annat exempel kan vara en robot som vill hämta tusentals dokument för att sedan indexera. Om detta inte skulle ske parallellt så skulle detta ta enormt mycket längre tid.&lt;/p&gt;

&lt;h2&gt;&lt;em&gt;PHP&lt;/em&gt; och &lt;em&gt;libcurl&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;PHP (och &lt;strong&gt;många&lt;/strong&gt; andra språk) har stöd för biblioteket &lt;a href="http://curl.haxx.se/" title="cURL and libcurl" rel="external nofollow" target="_blank"&gt;libcurl&lt;/a&gt;. Med &lt;em&gt;libcurl&lt;/em&gt; är det väldigt enkelt att hämta filer genom olika protokoll samtidigt som det är riktigt kraftfullt och flexibelt eftersom du kan konfigurera det på så många olika sätt.&lt;/p&gt;

&lt;p&gt;Normalt när du hämtar en fil med libcurl använder du följande:&lt;/p&gt;

&lt;pre class="brush: php"&gt;&amp;lt;?php

// initiate libcurl.
if ($ch = curl_init('http://www.ifconfig.se/'))
{
  // configure libcurl.
  curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  curl_setopt($ch, CURLOPT_MAXREDIRS, 32);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

  // execute libcurl.
  $body = curl_exec($ch);

  // close nicely.
  curl_close($ch);
}

?&amp;gt;&lt;/pre&gt;

&lt;p&gt;Detta är ganska så mycket kod för något som &lt;strong&gt;file_get_contents()&lt;/strong&gt; kan göra på en rad. Dock kräver &lt;strong&gt;file_get_contents()&lt;/strong&gt; att &lt;a href="http://www.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen" title="php.ini: allow_url_fopen" rel="external nofollow" target="_blank"&gt;allow_url_fopen&lt;/a&gt; är aktiverat i php.ini, vilket enligt mig är en säkerhetsrisk. Dessutom får du betydligt mer kontroll med libcurl och du kan även konfigurera libcurl att hämta komprimerade filer, vilket i sig spar bandbredd.&lt;/p&gt;


&lt;h2&gt;Att hämta filer &lt;em&gt;parallellt&lt;/em&gt; med &lt;em&gt;libcurl&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;För att hämta filer parallellt måste man först initiera ett objekt, som vi sedan kan lägga till vanliga curl objekt till. När vi lagt till alla objekt så använder vi oss av &lt;strong&gt;curl_multi_exec()&lt;/strong&gt; för att hämta alla filerna samtidigt.&lt;/p&gt;

&lt;pre class="brush: php"&gt;&amp;lt;?php

// urls to fetch.
$urls = array(
  'http://www.ifconfig.se/',
  'http://www.facebook.com/',
  'http://www.twitter.com/',
  'http://www.youtube.com/',
  'http://www.google.com/'
);
$total = count($urls);

// initiate the multi-handler.
$cm = curl_multi_init();

// loop through all urls and initiate all objects.
for($i=0;$i&amp;lt;$total;$i++)
{
  // initiate a libcurl object for each url.
  $ch[$i] = curl_init($urls[$i]);

  // configure each object.
  curl_setopt($ch[$i], CURLOPT_AUTOREFERER, 1);
  curl_setopt($ch[$i], CURLOPT_FOLLOWLOCATION, 1);
  curl_setopt($ch[$i], CURLOPT_MAXREDIRS, 32);
  curl_setopt($ch[$i], CURLOPT_HEADER, 0);
  curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 1);

  // add this object to the multi-handler.
  curl_multi_add_handle($cm, $ch[$i]);
}

// execute the multi-handler.
while(!isset($threads) || $threads &gt; 0)
{
  curl_multi_exec($cm, $threads);
}

// loop through the result and close nicely.
for($i=0;$i&amp;lt;$total;$i++)
{
  // get the result and some useful information.
  $body = curl_multi_getcontent($ch[$i]);
  $info = curl_getinfo($ch[$i]);

  // remove the handler and close it.
  curl_multi_remove_handle($cm, $ch[$i]);
  curl_close($ch[$i]);

  // print some information/statistics.
  printf("%s: %s (%ssec, %sKB, %s redirects)\n",
    $info['http_code'],
    $info['url'],
    round($info['total_time'], 2),
    round($info['size_download'] / 1024, 2),
    $info['redirect_count']
  );
}

// close the multi-handler.
curl_multi_close($cm);

?&amp;gt;&lt;/pre&gt;

&lt;p&gt;Detta script kommer köra alla 5 förfrågningar samtidigt och därefter skriva ut lite information om varje &lt;abbr title="Universal Resource Location"&gt;URL&lt;/abbr&gt;. Med funktionen &lt;a href="http://www.php.net/manual/en/function.curl-getinfo.php" title="PHP Functions: curl_getinfo()" rel="external nofollow"&gt;curl_getinfo()&lt;/a&gt; får vi ut användbar information om själva förfrågan till servern samt lite meta-data så som storlek, kodning, osv. Om du har PHP installerat för &lt;abbr title="Command Line Interface"&gt;CLI&lt;/abbr&gt;, så kan du köra det direkt i shellet.&lt;/p&gt;

&lt;pre class="brush: bash"&gt;php ./curl-multi.php
200: http://www.ifconfig.se/ (0.48sec, 56.07KB, 0 redirects)
200: http://www.facebook.com/common/browser.php (1.08sec, 11.24KB, 1 redirects)
200: http://twitter.com/ (1.9sec, 43.29KB, 1 redirects)
200: http://www.youtube.com/ (0.62sec, 79.82KB, 0 redirects)
200: http://www.google.se/ (0.62sec, 10.54KB, 1 redirects)&lt;/pre&gt;&lt;br /&gt;


&lt;h2&gt;Avslut&lt;/h2&gt;
&lt;p&gt;Att använda &lt;em&gt;libcurl&lt;/em&gt; gör att man får enormt mycket kontroll över själva filhämtningen samtidigt som det är smidigt att konfigurera. Det stödjer dessutom enormt många protokoll så som &lt;abbr title="Hypertext Transfer Protocol"&gt;HTTP&lt;/abbr&gt;, &lt;abbr title="File Transfer Protocol"&gt;FTP&lt;/abbr&gt;, &lt;abbr title="Secure Shell"&gt;SSH&lt;/abbr&gt;/&lt;abbr title="Secure Copy"&gt;SCP&lt;/abbr&gt;, &lt;abbr title="Internet Message Access Protocol"&gt;IMAP&lt;/abbr&gt;, &lt;abbr title="Post Office Protocol"&gt;POP3&lt;/abbr&gt;, m.fl.&lt;/p&gt;

&lt;p&gt;En annan smidig funktion med &lt;em&gt;libcurl&lt;/em&gt; är att oavsett om du hämtar en fil som är komprimerad (gzip, deflate, etc), så kommer alla &lt;em&gt;cURL&lt;/em&gt;-funktioner ändå returnera den okomprimerade filen. Detta gör att man enkelt kan ignorera hela processen med att kontrollera om filen är komprimerad eller inte.&lt;/p&gt;

&lt;p&gt;Hur använder du själv cURL och framför allt, i vilket språk använder du det i? Personligen har jag främst använt cURL ihop med PHP, då många av de andra språken jag använder har egna funktioner för just det jag behöver.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/T8xmMbqUwjQ" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/php-curl-parallellt</feedburner:origLink></entry>
  <entry>
    <id>http://www.ifconfig.se/script-taggar-javascript</id>
    <published>2011-01-02T01:47:00+01:00</published>
    <updated>2012-02-13T10:38:17+01:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/5He8ZxbZLjU/script-taggar-javascript" />
    <title>Att skriva script-taggar med JavaScript</title>
    <content type="html">&lt;h2&gt;Introduktion&lt;/h2&gt;
&lt;p&gt;För en tid sedan kom jag i kontakt med ett ganska så ovanligt problem. Jag skulle ladda ett &lt;em&gt;JavaScript&lt;/em&gt; i en lightbox, som i sin tur laddades av ett JavaScript. Dvs, jag skulle skriva ut en &amp;lt;script&amp;gt;-tag med hjälp av JavaScript.&lt;/p&gt;

&lt;p&gt;Både Chrome och Firefox slutade att läsa mitt JavaScript så fort jag skrev ut en &amp;lt;/script&amp;gt;-tag, då båda webbläsarna helt korrekt antog att JavaScriptet var slut.&lt;/p&gt;

&lt;pre class="brush: javascript"&gt;&amp;lt;script type="text/javascript"&amp;gt;
$(document).ready(function(){
  $.lightbox('&amp;lt;script type="text/javascript" src="/some/file.js"&amp;gt;&amp;lt;/script&amp;gt;');
});
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;Koden ovan kommer sluta läsas av webbläsaren efter den första &amp;lt;/script&amp;gt;-taggen och därmed tolka scriptet som felaktigt, då det avbryts mitt i en funktion.&lt;/p&gt;


&lt;h2&gt;Lösningen på problemet&lt;/h2&gt;
&lt;p&gt;Jag har tidigare sett denna lösning användas på många webbplatser, men jag har alltid varit övertygad om att det har varit ett annonsnätverk eller liknande som försöker rundgå plugins så som AdBlock, NoScript, osv.&lt;/p&gt;

&lt;pre class="brush: javascript"&gt;&amp;lt;script type="text/javascript"&amp;gt;
$(document).ready(function(){
  $.lightbox('&amp;lt;scr' + 'ipt type="text/javascript" src="/some/file.js"&amp;gt;&amp;lt;/scri' + 'pt&amp;gt;');
});
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;Genom att helt enkelt bara dela taggen &lt;em&gt;&amp;lt;/script&amp;gt;&lt;/em&gt; till två strängar och sen sätta ihop dem med hjälp av JavaScriptet, så tolkar webbläsaren det som &lt;em&gt;&amp;lt;/scri&lt;/em&gt; och &lt;em&gt;pt&amp;gt;&lt;/em&gt; istället för &lt;em&gt;&amp;lt;/script&amp;gt;&lt;/em&gt; och avslutar därmed inte scriptet.&lt;/p&gt;

&lt;p&gt;Som en liten notering kan det väl vara värt att nämna att ett JavaScript i en lightbox inte kommer köras oavsett och nu i efterhand kan jag väl lugnt säga att det var en ganska så kass approach på det hela. ;-)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/5He8ZxbZLjU" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/script-taggar-javascript</feedburner:origLink></entry>
  <entry>
    <id>http://www.ifconfig.se/cloaking-google</id>
    <published>2010-12-30T03:42:00+01:00</published>
    <updated>2012-02-13T10:24:57+01:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/g_X-P5t1gRA/cloaking-google" />
    <title>Google tar hårdare tag mot Cloaking</title>
    <content type="html">&lt;h2&gt;Vad är Cloaking?&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Cloaking&lt;/em&gt; är det begrepp &lt;a href="http://www.google.com/support/webmasters/bin/answer.py?hl=en&amp;amp;answer=66355" title="Cloaking, sneaky JavaScript redirects and doorway pages" target="_blank" rel="external nofollow"&gt;Google använder&lt;/a&gt; när man inte presenterar samma innehåll till &lt;em&gt;Google&lt;/em&gt; som till övriga användare. Google ser allvarligt på detta och du riskerar att bli borttagen helt ur &lt;acronym title="Search Engine Result Pages"&gt;SERP&lt;/acronym&gt;:en om du använder dig av &lt;em&gt;cloaking&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Om du inte vill att Google ska besöka eller indexera vissa delar av din webbplats, så rekommenderar jag istället att du använder dig av &lt;a href="http://www.robotstxt.org/robotstxt.html" title="The /robots.txt" rel="external nofollow" target="_blank"&gt;robots.txt&lt;/a&gt; eller en &lt;a href="http://www.robotstxt.org/meta.html" title="Robots Meta Tags" rel="external nofollow" target="_blank"&gt;robots meta&lt;/a&gt;-tag.&lt;/p&gt;


&lt;h2&gt;Hårdare tag mot Cloaking i början av 2011&lt;/h2&gt;
&lt;p&gt;Google kommer, enligt &lt;a href="http://twitter.com/#!/mattcutts/status/19152836789014528" title="Matt Cutts: Tweet" target="_blank" rel="external nofollow"&gt;Matt Cutts&lt;/a&gt;, att ta hårdare tag mot &lt;em&gt;cloaking&lt;/em&gt; i början av 2011.&lt;/p&gt;

&lt;p&gt;För att kontrollera om man behandlar Googlebot annorlunda på något sätt så kommer man nu även granska alla &lt;strong&gt;headers&lt;/strong&gt; och &lt;strong&gt;redirects&lt;/strong&gt; på webbplatsen. Min gissning är också att denna ändring kommer vara bestående om den fungerar bra.&lt;/p&gt;

&lt;p&gt;Personligen ser jag inte varför man skulle behöva hantera Googlebot på något annorlunda sätt jämfört med vanliga användare. Om detta är ett &lt;em&gt;måste&lt;/em&gt; så kanske det är dags att se över vilka metoder man använder för att få sin sida indexerad. ;-)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/g_X-P5t1gRA" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/cloaking-google</feedburner:origLink></entry>
  <entry>
    <id>http://www.ifconfig.se/fulltext-postgresql</id>
    <published>2010-12-26T22:13:00+01:00</published>
    <updated>2012-02-24T21:50:21+01:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/fBRNuOwkWWs/fulltext-postgresql" />
    <title>Fulltext sök med PostgreSQL</title>
    <content type="html">&lt;h2&gt;Vad är Fulltext sök?&lt;/h2&gt;
&lt;p&gt;Fulltext sök är en funktion som erbjuder möjligheten att söka i en tabell och hitta de rader som matchar en specifik &lt;em&gt;fråga&lt;/em&gt;. Fulltext låter dig även ranka resultatet efter vilket relevans och likhet &lt;em&gt;frågan&lt;/em&gt; har till texten man söker i.&lt;/p&gt;

&lt;p&gt;Fulltext sök låter dig göra en mer fördjupad sökning än vanliga funktioner så som &lt;a href="http://www.postgresql.org/docs/8.4/static/functions-matching.html#FUNCTIONS-LIKE" title="Pattern Matching" rel="external nofollow" target="_blank"&gt;&lt;em&gt;LIKE&lt;/em&gt;&lt;/a&gt;, som enbart söker efter ett ord eller en fras i texten. LIKE är dessutom väldigt prestandakrävande eftersom den inte använder något &lt;strong&gt;index&lt;/strong&gt;, utan måste gå igenom alla rader i tabellen vid &lt;strong&gt;varje&lt;/strong&gt; sökning.&lt;/p&gt;

&lt;p&gt;Så som PostgreSQL har implementerat Fulltext, så tar den även hänsyn till vilket &lt;strong&gt;språk&lt;/strong&gt; som används och kan därför också ta hänsyn till hur olika ord är &lt;strong&gt;böjda&lt;/strong&gt; (&lt;em&gt;ringa&lt;/em&gt; vs &lt;em&gt;ringer&lt;/em&gt; vs &lt;em&gt;ringde&lt;/em&gt;). Den ignorerar även så kallade &lt;strong&gt;stopwords&lt;/strong&gt;, ord som används för ofta för att vara användbara vid en sökning (&lt;em&gt;och&lt;/em&gt;, &lt;em&gt;är&lt;/em&gt;, &lt;em&gt;har&lt;/em&gt;, osv). Den klarar även av att hantera &lt;strong&gt;synonymer&lt;/strong&gt; (&lt;em&gt;glad&lt;/em&gt; vs &lt;em&gt;lycklig&lt;/em&gt;) vilket man också kan använda för att korrigera vanligt förekommande stavfel.&lt;/p&gt;


&lt;h2&gt;Datatyper och normalisering&lt;/h2&gt;
&lt;p&gt;PostgreSQL använder datatyperna &lt;a href="http://www.postgresql.org/docs/8.4/static/datatype-textsearch.html#DATATYPE-TSVECTOR" title="Datatype: tsvector" rel="external nofollow" target="_blank"&gt;tsvector&lt;/a&gt; och &lt;a href="http://www.postgresql.org/docs/8.4/static/datatype-textsearch.html#DATATYPE-TSQUERY" title="Datatype: tsquery" rel="external nofollow" target="_blank"&gt;tsquery&lt;/a&gt; för att hantera den data som används när du utför en sökning. Typen &lt;em&gt;tsvector&lt;/em&gt; innehåller den representation av texten som man ska söka i, medan &lt;em&gt;tsquery&lt;/em&gt; innehåller motsvarande data för &lt;em&gt;frågan&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;to_tsvector()&lt;/h3&gt;
&lt;p&gt;För att kunna använda den oformaterade texten i en vanlig kolumn så finns funktionen &lt;em&gt;to_tsvector()&lt;/em&gt; som konverterar text till datatypen &lt;em&gt;tsvector&lt;/em&gt;. En &lt;em&gt;tsvector&lt;/em&gt; innehåller en sorterad lista med alla unika &lt;em&gt;lexemer&lt;/em&gt; och vilken position i texten ordet har. Lexemer är normaliserade ord där alla stopwords blivit borttagna och synonymer samt böjelser har blivit sammanslagna.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT to_tsvector('swedish', 'Sex laxar i en vaxad laxask');
               to_tsvector                
------------------------------------------
 'ask':6 'e':4 'lax':2,6 'sex':1 'vaxa':5&lt;/pre&gt;

&lt;h3&gt;to_tsquery()&lt;/h3&gt;
&lt;p&gt;Funktionen &lt;em&gt;to_tsquery()&lt;/em&gt; används för att skapa en lista av de &lt;em&gt;lexemer&lt;/em&gt; som man ska söka efter i en &lt;em&gt;tsvector&lt;/em&gt;. Denna listan är också sorterad efter &amp;amp; (AND), | (OR) och ! (NOT) som används för att matcha fler/färre rader. Det går även att gruppera dessa operatorer med hjälp av parenteser.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT to_tsquery('swedish', 'laxarna &amp;amp; vaxar &amp;amp; asken');
         to_tsquery
-----------------------
 'lax' &amp;amp; 'vax' &amp;amp; 'ask'&lt;/pre&gt;

&lt;p&gt;Man kan även använda funktionen &lt;em&gt;plainto_tsquery()&lt;/em&gt; som konverterar oformaterad text till en &lt;em&gt;tsquery&lt;/em&gt;, dock kan man inte använda sig av &amp;amp; (AND), | (OR) eller ! (NOT) här.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT plainto_tsquery('swedish', 'laxarna vaxar asken');
    plainto_tsquery
-----------------------
 'lax' &amp;amp; 'vax' &amp;amp; 'ask'&lt;/pre&gt;

&lt;p&gt;Gemensamt för funktionerna ovan är att det första argumentet anger vilken &lt;a href="http://www.postgresql.org/docs/8.4/static/textsearch-intro.html#TEXTSEARCH-INTRO-CONFIGURATIONS" title="Full Text Search Configurations" rel="external nofollow" target="_blank"&gt;konfiguration&lt;/a&gt; man ska använda. Du kan lista alla standardkonfigurationerna genom att skriva &lt;kbd&gt;\dF[+]&lt;/kbd&gt; i &lt;a href="http://www.postgresql.org/docs/8.4/static/app-psql.html" title="PostgreSQL interactive terminal" target="_blank" rel="external nofollow"&gt;&lt;kbd&gt;psql&lt;/kbd&gt;&lt;/a&gt;. Beroende på vilken konfiguration du använder så normaliseras texten olika.&lt;/p&gt;


&lt;h2&gt;Att utföra en sökning&lt;/h2&gt;
&lt;p&gt;För att göra en sökning så använder man operatorn &lt;a href="http://www.postgresql.org/docs/8.4/static/functions-textsearch.html#TEXTSEARCH-OPERATORS-TABLE" title="Text Search Operators" rel="external nofollow" target="_blank"&gt;@@&lt;/a&gt; och jämför &lt;em&gt;tsvector&lt;/em&gt; med &lt;em&gt;tsquery&lt;/em&gt; och får då tillbaks &lt;em&gt;true&lt;/em&gt; eller &lt;em&gt;false&lt;/em&gt; beroende på om dom matchar eller inte.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT to_tsvector('swedish', 'Sex laxar i en vaxad laxask') @@
    plainto_tsquery('swedish', 'laxar') AS result;
 result 
--------
 t&lt;/pre&gt;

&lt;p&gt;Åter igen så hanterar hanterar &lt;em&gt;Fulltext&lt;/em&gt; olika böjelser av orden:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT to_tsvector('swedish', 'Sex laxar i en vaxad laxask') @@
    plainto_tsquery('swedish', 'laxarna vaxar asken') AS result;
 result 
--------
 t&lt;/pre&gt;

&lt;p&gt;För att söka i en kolumn, t.ex &lt;em&gt;posts&lt;/em&gt;, så anger man helt enkelt kolumnen:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT to_tsvector('swedish', posts) @@
    plainto_tsquery('swedish', 'sökord') AS result;
 result 
--------
 t&lt;/pre&gt;&lt;br /&gt;


&lt;h2&gt;Ranka resultatet&lt;/h2&gt;
&lt;p&gt;När man söker och matchar flera hundra eller tusen rader så kan det vara smidigt att sortera efter relevans. För att göra detta använder man funktionerna &lt;em&gt;ts_rank()&lt;/em&gt; och &lt;em&gt;ts_rank_cd()&lt;/em&gt;.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT title, ts_rank_cd(to_tsvector('swedish', content), query, 16) AS rank 
   FROM posts, to_tsquery('swedish', 'FreeBSD') query
   WHERE query @@ to_tsvector('swedish', content) ORDER BY rank DESC;

                 title                  |   rank    
----------------------------------------+-----------
 Virtualisera med KVM i Ubuntu 9.10     | 0.0887506
 Ports i FreeBSD                        | 0.0729145
 FreeBSD 8.0 och rc.conf                | 0.0132641&lt;/pre&gt;

&lt;p&gt;Båda funktionerna tar hänsyn till hur ofta ordet nämns i texten, textens storlek samt även hur viktig delen av texten är där ordet förekommer. Det som skiljer de båda funktionerna åt, är att &lt;em&gt;ts_rank_cd()&lt;/em&gt; även tar hänsyn till hur många ord som finns mellan varje sökord, dvs, hur hög densitet texten har. (&lt;em&gt;cd = cover density&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;Du kan även ange hur viktig olika delar av texten du söker i är, samt ange hur längden på texten ska påverka rankingen. För mer information om detta, läs &lt;a href="http://www.postgresql.org/docs/8.4/static/textsearch-controls.html#TEXTSEARCH-RANKING" title="Ranking Search Result" rel="external nofollow" target="_blank"&gt;dokumentationen&lt;/a&gt;.&lt;/p&gt;


&lt;h2&gt;Markera sökord i resultatet&lt;/h2&gt;
&lt;p&gt;Något som sökmotorer ofta gör är att presentera sökresultat där man markerar sökorden med fet stil eller liknande. På så sätt kan man enkelt se hur &lt;em&gt;frågan&lt;/em&gt; man ställt är relaterad till texten den matchat. Funktionen &lt;a href="http://www.postgresql.org/docs/8.4/static/textsearch-controls.html#TEXTSEARCH-HEADLINE" title="Highlighting Results" rel="external nofollow" target="_blank"&gt;ts_headline()&lt;/a&gt; gör just detta:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT ts_headline('swedish',title, query), rank FROM
  (SELECT title, query, ts_rank_cd(to_tsvector('swedish', title), query, 16) AS rank 
   FROM posts, to_tsquery('swedish', 'FreeBSD | rc.conf') query
   WHERE query @@ to_tsvector('swedish', title) ORDER BY rank DESC) AS foo;

              ts_headline              |   rank   
---------------------------------------+----------
 &amp;lt;b&amp;gt;FreeBSD&amp;lt;/b&amp;gt; 8.0 och &amp;lt;b&amp;gt;rc.conf&amp;lt;/b&amp;gt; |      0.1
 Ports i &amp;lt;b&amp;gt;FreeBSD&amp;lt;/b&amp;gt;                | 0.063093
 &amp;lt;b&amp;gt;FreeBSD&amp;lt;/b&amp;gt; 8.0 och sysctl.conf    |     0.05&lt;/pre&gt;

&lt;p&gt;Anledningen till att man använder en sub-query här är för att ts_headline() självklart måste använda original texten för att markera de ord man söker efter. Om du inte använder en sub-query måste detta göras på &lt;strong&gt;alla&lt;/strong&gt; rader i tabellen, vilket är väldigt prestandakrävande beroende på hur mycket data du har.&lt;/p&gt;

&lt;p&gt;Hur texten ska markeras och antalet ord som ska finnas med före och efter sökordet går att konfigurera på en mängd olika sätt, jag kan även här rekommendera att du läser igenom &lt;a href="http://www.postgresql.org/docs/8.4/static/textsearch-controls.html#TEXTSEARCH-HEADLINE" title="Highlighting Results" rel="external nofollow" target="_blank"&gt;dokumentationen&lt;/a&gt;.&lt;/p&gt;


&lt;h2&gt;Begränsningar&lt;/h2&gt;
&lt;p&gt;Även om denna implementation av PostgreSQL är riktigt kraftfull så har den självklart en del begränsningar. Något som jag rent spontant kan sakna, är möjligheten att söka på exakta fraser. Man kan självklart använda &amp;amp; (AND), men detta betyder ju inte att orden står i följd. Det andra är mer tekniska begränsningar som har med storlek att göra:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Storleken på varje &lt;em&gt;lexem&lt;/em&gt; får max vara 2KB&lt;/li&gt;
  &lt;li&gt;Storleken på &lt;em&gt;tsvector&lt;/em&gt; (alla lexemer och dess position i texten) får max vara 1MB&lt;/li&gt;
  &lt;li&gt;Max antal &lt;em&gt;lexemer&lt;/em&gt; måste vara mindre än 2&lt;sup&gt;64&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;Positionen på en &lt;em&gt;laxem&lt;/em&gt; måste vara högre än 0 och mindre än 16,383&lt;/li&gt;
  &lt;li&gt;Max antalet position en lexem kan ha är 256&lt;/li&gt;
  &lt;li&gt;Antalet noder (lexermer och operatorer) i en &lt;em&gt;tsquery&lt;/em&gt; 32,768&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Avslut&lt;/h2&gt;
&lt;p&gt;Jag är personligen kär i hur PostgreSQL har implementerat ett &lt;em&gt;Fulltext&lt;/em&gt; sök. Den är oerhört snabb, skalar enormt bra, väldigt kraftfull och går att konfigurera på en mängd olika sätt. Jag använder just denna implementation av Fulltext sök för att hitta relaterade artiklar på inlägg/artiklar jag gör här på bloggen. På så sätt uppdateras det automatiskt och jag får faktiskt artiklar som är relaterade på riktigt och inte som många WordPress plugin gör och använder kommentarer(!?) ihop med kategorier/taggar för att avgöra om innehållet är relaterat eller inte.&lt;/p&gt;

&lt;p&gt;Ett annat tips är att skapa en kolumn med datatypen &lt;em&gt;tsvector&lt;/em&gt; och köra &lt;em&gt;to_tsvector()&lt;/em&gt; vid &lt;em&gt;INSERT&lt;/em&gt; och &lt;em&gt;UPDATE&lt;/em&gt; istället. På så sätt har du redan normaliserat texten och slipper därför göra detta varje gång du ska söka i tabellen. Du bör även skapa ett &lt;a href="http://www.postgresql.org/docs/8.4/interactive/gin.html" title="GIN Indexes" rel="external nofollow" target="_blank"&gt;GIN-index&lt;/a&gt; om du har mycket data för att maximera prestandan.&lt;/p&gt;

&lt;p&gt;Notera också att jag har ändrat mina &lt;em&gt;Fulltext&lt;/em&gt; konfigurationer en aning, så resultaten ovan kan skilja lite från standardinställningarna i PostgreSQL.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/fBRNuOwkWWs" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/fulltext-postgresql</feedburner:origLink></entry>
  <entry>
    <id>http://www.ifconfig.se/order-by-rand</id>
    <published>2010-12-23T22:05:00+01:00</published>
    <updated>2012-02-14T03:10:28+01:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/N1Ha916Zg0Y/order-by-rand" />
    <title>Prestanda och ORDER BY RAND() </title>
    <content type="html">&lt;h2&gt;Använd inte &lt;em&gt;ORDER BY RAND()&lt;/em&gt; om du har många rader i tabellen&lt;/h2&gt;
&lt;p&gt;För att få ut 10 rader i slumpad ordning från en tabell i MySQL så använder man väldigt ofta funktionen &lt;em&gt;ORDER BY RAND()&lt;/em&gt; ihop med &lt;em&gt;LIMIT&lt;/em&gt;:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT uid, username, passwd FROM users ORDER BY RAND() LIMIT 10;&lt;/pre&gt;

&lt;p&gt;Detta är ingen fara så länge det handlar om mindre data (~250 rader) men vad händer om du ställer samma fråga till en tabell med 25000 rader? Då kommer MySQL generera 25000 slumpade tal, vilket är ganska så tungt ur prestandasynpunkt. Därefter behöver MySQL sortera dessa 25000 tal för att veta vilket tal som är lägst, vilket också är tungt då MySQL skapar temporära tabeller för detta.&lt;/p&gt;

&lt;p&gt;Något som kan vara värt att poängtera är att om &lt;strong&gt;uid&lt;/strong&gt;, &lt;strong&gt;username&lt;/strong&gt; och &lt;strong&gt;passwd&lt;/strong&gt; har en fast längd (&lt;em&gt;varchar&lt;/em&gt;, &lt;em&gt;int&lt;/em&gt;, &lt;em&gt;date&lt;/em&gt;, etc) så går det snabbare att sortera. Om den har en rörlig längd (&lt;em&gt;text&lt;/em&gt;) måste MySQL även gå igenom alla rader innan för att veta hur mycket minne som behöver allokeras för den temporära tabellen som kommer skapas.&lt;/p&gt;

&lt;h2&gt;En av många lösningar på detta problem&lt;/h2&gt;
&lt;p&gt;Lösningen på detta problem är långt ifrån enkel och förmodligen inte heller optimal. Istället för att sortera all data i MySQL och för att slippa hämta all data och sortera den i applikationen, så hämtar vi bara det högsta och lägsta &lt;strong&gt;uid&lt;/strong&gt;.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;SELECT MIN(uid) AS min, MAX(uid) AS max FROM users;&lt;/pre&gt;

&lt;p&gt;Därefter använder vi &lt;a href="http://www.php.net/" title="PHP: Hypertext Preprocessor" target="_blank" rel="external nofollow"&gt;PHP&lt;/a&gt; för att slumpa 10 tal mellan &lt;em&gt;min&lt;/em&gt; och &lt;em&gt;max&lt;/em&gt;. Funktionen &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_in" title="Comparison Operators" target="_blank" rel="external nofollow"&gt;&lt;em&gt;IN()&lt;/em&gt;&lt;/a&gt; i MySQL gör det dessutom enkelt att endast hämta de 10 rader vi slumpat fram utan att behöva använda en massa &lt;em&gt;AND&lt;/em&gt;. Detta gör att vi inte behöver använda &lt;em&gt;ORDER BY RAND()&lt;/em&gt; alls.&lt;/p&gt;

&lt;pre class="brush: php"&gt;&amp;lt;?php

// get the first/last row of the table.
$sql = "SELECT MIN(uid) AS min, MAX(uid) AS max FROM users";
$res = mysql_query($sql);
$row = mysql_fetch_object($res);

// get 10 random rows and skip ORDER BY RAND() completely.
for ($i=0;$i&amp;lt;10;$i++)
{
    $users[$i] = rand($row-&amp;gt;min, $row-&amp;gt;max);
}

// fetch those 10 random rows.
$sql = sprintf("SELECT uid, username, passwd FROM users WHERE uid IN(%s)",
    implode(',', $users)
);
$res = mysql_query($sql);&lt;/pre&gt;&lt;br /&gt;


&lt;h2&gt;Borttagna rader&lt;/h2&gt;
&lt;p&gt;Om du har raderat några rader ur tabellen och därför inte får ut alla 10 rader, då kan du enkelt slumpa fram fler tal med &lt;abbr title="PHP: Hypertext Preprocessor"&gt;PHP&lt;/abbr&gt; och sedan använda &lt;em&gt;LIMIT 10&lt;/em&gt;.&lt;/p&gt;

&lt;pre class="brush: php"&gt;// get 100 random rows.
for ($i=0;$i&amp;lt;100;$i++)
{
    $users[$i] = rand($row-&amp;gt;min, $row-&amp;gt;max);
}

// fetch those 100 random rows, but limit the result to 10 rows.
$sql = sprintf("SELECT uid, username, passwd FROM users WHERE uid IN(%s) LIMIT 10",
    implode(',', $users)
);
$res = mysql_query($sql);

?&amp;gt;&lt;/pre&gt;

&lt;p&gt;Även om denna lösning kanske inte är helt optimalt så är den betydligt snabbare än att enbart använda &lt;em&gt;ORDER BY RAND() LIMIT 10&lt;/em&gt; om du har tiotusentals rader. En annan lösning är att skapa en till kolumn och fylla den med slumpade tal som man sedan sorterar efter när man läser ur tabellen. Dessvärre måste man generera om alla tal i denna kolumn varje gång man vill ändra ordningen på resultatet, vilket gör att jag personligen väljer bort den lösningen.&lt;/p&gt;

&lt;p&gt;Har du någon bättre lösning eller tips på hur man kan lösa detta problem?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/N1Ha916Zg0Y" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/order-by-rand</feedburner:origLink></entry>
  <entry>
    <id>http://www.ifconfig.se/ta-vara-inlankar</id>
    <published>2010-12-19T20:12:00+01:00</published>
    <updated>2012-02-09T11:20:09+01:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/TVNnTAnjp7U/ta-vara-inlankar" />
    <title>Ta vara på alla dina inlänkar</title>
    <content type="html">&lt;h2&gt;Inlänkar och PageRank&lt;/h2&gt;
&lt;p&gt;Som du säkert redan vet är inlänkar en av de viktigaste faktorerna när det gäller att ranka bra i sökresultatet. Inlänkar är det som &lt;a href="http://en.wikipedia.org/wiki/PageRank" title="How PageRank is calculated" rel="external nofollow" target="_blank"&gt;PageRank&lt;/a&gt; baserar sitt värde på och avgör hur viktig en webbplats är. Självklart är det flera &lt;em&gt;hundra&lt;/em&gt; andra faktorer som också granskas när Google avgör vart din webbplats hamnar i sökresultetet.&lt;/p&gt;

&lt;p&gt;Det är ingen nyhet för &lt;acronym title="Search Engine Optimization"&gt;SEO&lt;/acronym&gt;-expeter att inlänkar med högre &lt;abbr title="PageRank"&gt;PR&lt;/abbr&gt; är bättre än inlänkar med låg &lt;abbr title="PageRank"&gt;PR&lt;/abbr&gt;. Dock så är ju en inlänk alltid en inlänk och det vore dumt att inte ta vara på den om den pekar till en sida som inte finns längre.&lt;/p&gt;


&lt;h2&gt;Hitta brutna inlänkar&lt;/h2&gt;
&lt;p&gt;Google's &lt;a href="http://www.google.com/webmasters/tools/" title="Google Webmasters Tools" rel="external nofollow" target="_blank"&gt;Webmasters Tools&lt;/a&gt; erbjuder möjligheten att hitta brutna inlänkar på din webbplats. Personligen tycker att Webmasters Tools fungerar relativt dåligt och visar ofta gammal data. Ett bättre alternativ för att just hitta brutna inlänkar är att analysera loggarna från din webbserver. Självklart kräver det att någon har försökt besöka den, men chansen är ganska stor att åtminstone en robot har försökt besöka sidan.&lt;/p&gt;

&lt;p&gt;Med hjälp av &lt;strong&gt;grep&lt;/strong&gt;, &lt;strong&gt;awk&lt;/strong&gt; och &lt;strong&gt;sort&lt;/strong&gt; kan vi enkelt få ut alla brutna länkar:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;grep ' 404 ' /path/to/access.log | awk '{ if ($11 != "\"-\"") { print $7 } }' | sort -u
/verifiera-googlebot
/phpmyadmin2/config/config.inc.php?p=phpinfo();
/randomqb
/wp-signup.php
...&lt;/pre&gt;

&lt;p&gt;Nackdelen med din webbservers loggar är att du ser &lt;em&gt;alla&lt;/em&gt; brutna länkar, eller rättare sagt, &lt;em&gt;alla&lt;/em&gt; sidor som någon försökt besöka och som inte hittats på webbservern. Detta inkluderar alla länkar som vissa program försöker hitta när de letar efter webb-applikationer med kända säkerhetshål.&lt;/p&gt;

&lt;p&gt;Ovan ser du t.ex en länk till phpMyAdmin och en länk till WordPress registrerings-formulär, två länkar som jag vet är felaktiga eftersom jag varken använder PHP eller MySQL på denna blogg. Däremot ser jag en bruten länk som förmodligen ska gå till min artikel om hur du &lt;a href="http://www.ifconfig.se/identifiera-googlebot" title="Verifiera en Googlebot" rel="internal"&gt;identifierar en Googlebot&lt;/a&gt;.&lt;/p&gt;


&lt;h2&gt;Omdirigera och ta vara på dom brutna länkarna&lt;/h2&gt;
&lt;p&gt;Eftersom dessa inlänkar är brutna så får du självklart ingen PageRank från dem. För att ta vara på dessa länkar så kan du enkelt omdirigera trafiken till den sidan som känns mest korrekt. Om du är osäker på vilken sida som är mest korrekt, så omdirigera trafiken till startsidan bara.&lt;/p&gt;

&lt;p&gt;Nedan är ett exempel på hur du kan använda &lt;a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html" title="Apache: mod_rewrite" target="_blank" rel="external nofollow"&gt;Apache's mod_rewrite&lt;/a&gt; modul för att omdirigera trafik. Om det &lt;acronym title="Content Management System"&gt;CMS&lt;/acronym&gt; du använder klarar av att göra detta, så kan du självklart använda det istället.&lt;/p&gt;

&lt;pre class="brush: bash"&gt;# Rewrite URL-typos
RewriteEngine On
RewriteRule ^/randomgb http://www.ifconfig.se/ [R=301,L]
RewriteRule ^/verifiera-googlebot http://www.ifconfig.se/identifiera-googlebot [R=301,L]
...
&lt;/pre&gt;

&lt;p&gt;Detta kommer skicka användaren (och Google) till den korrekta sidan och du får då några fler inlänkar till din webbplats och därmed lite mer PageRank. Du ska självklart inte omdirigera all trafik till sidor som inte finns, men om någon länkar till en sida som uppenbarligen inte finns, så kan det vara klokt att fixa detta.&lt;/p&gt;


&lt;h2&gt;Automatisera detta&lt;/h2&gt;
&lt;p&gt;Ett vanligt misstag när man länkar till andra sidor är att man missar en bokstav eller två av länken och därmed får en bruten länk av misstag. För att lösa detta har verktyg så som WordPress gjort så att man automatiskt söker efter en sida med liknande länk om du hamnar på en sida som inte finns.&lt;/p&gt;

&lt;p&gt;Personligen gör jag precis samma sak på denna blogg, besöker du t.ex &lt;a href="http://www.ifconfig.se/overbel" title="Vad exakt är en överbelastningsattack?" rel="internal"&gt;en halv adress&lt;/a&gt; så kommer du automatiskt skickas vidare till &lt;a href="http://www.ifconfig.se/overbelastningsattacker-1" title="Överbelastningsattacker" rel="internal"&gt;korrekt artikel&lt;/a&gt; om den hittas. Om den inte hittas så visas min vanliga &lt;em&gt;404&lt;/em&gt;-sida.&lt;/p&gt;

&lt;p&gt;Hur hanterar du själv brutna inlänkar på din webbplats?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/TVNnTAnjp7U" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/ta-vara-inlankar</feedburner:origLink></entry>
  <entry>
    <id>http://www.ifconfig.se/overbelastningsattacker-1</id>
    <published>2010-12-15T23:22:00+01:00</published>
    <updated>2012-02-13T10:05:23+01:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/krid_cPiJ_s/overbelastningsattacker-1" />
    <title>Överbelastningsattacker (del 1)</title>
    <content type="html">&lt;h2&gt;Introduktion&lt;/h2&gt;
&lt;p&gt;Detta är den första delen i en artikelserie som kommer inrikta sig på överbelastningsattacker. Jag kommer gå igenom om hur du skyddar dig emot dessa och generell &lt;em&gt;best practice&lt;/em&gt; när det gäller att konfigurera en brandvägg och filtrera trafik.&lt;/p&gt;

&lt;p&gt;Den första artikeln kommer ta upp vilka typer av överbelastningsattacker som är vanligast, vad dessa attacker innehåller samt vilka svagheter dessa attacker utnyttjar.&lt;/p&gt;


&lt;h2&gt;Olika former av överbelastningsattacker&lt;/h2&gt;
&lt;p&gt;Ofta beskriver media alla former av överbelastningsattacker som &lt;abbr title="Distributed Denial of Service"&gt;DDoS&lt;/abbr&gt;-attacker, utan att dom egentligen vet vilken typ av attack det handlar om. De 3 vanligaste formerna av överbelastningsattacker är &lt;abbr title="Denial of Service"&gt;DoS&lt;/abbr&gt;, &lt;abbr title="Distributed Denial of Service"&gt;DDoS&lt;/abbr&gt; och &lt;abbr title="Distributed Reflection Denial of Service"&gt;DRDoS&lt;/abbr&gt;.&lt;/p&gt;

&lt;h3&gt;DoS &amp;ndash; Denial of Service&lt;/h3&gt;
&lt;p&gt;En &lt;abbr title="Denial of Service"&gt;DoS&lt;/abbr&gt;-attack är när &lt;strong&gt;en&lt;/strong&gt; angripare försöker göra en tjänst onåbar. Denna attack går oftast ut på att förbruka så mycket av offrets interna resurser som möjligt, så som minne och processorkraft. Eftersom en ensam angripare sällan har nog med bandbredd för att förbruka offrets bandbredd så försöker man istället utnyttja sårbarheter i mjukvara, konfiguration eller de protokoll som tjänsten använder.&lt;/p&gt;

&lt;h3&gt;DDoS &amp;ndash; Distributed Denial of Service&lt;/h3&gt;
&lt;p&gt;DDoS eller &lt;em&gt;Distributed Denial of Service&lt;/em&gt; som det betyder, är den typen av attack där &lt;strong&gt;flera&lt;/strong&gt; datorer tillsammans angriper samma tjänst. Här är det vanligast att man försöker överbelasta nätverket och använda all tillgänglig bandbredd för att göra en tjänsten onåbar.&lt;/p&gt;

&lt;p&gt;Den här typen av attacker sker oftast från vanliga hemma-datorer som infekterats med virus/trojaner för att skapa ett så kallat &lt;em&gt;botnät&lt;/em&gt;. De individer som är seriösa med DDoS brukar även hacka diverse servrar, routrar och annan utrustning som ofta har tillgång till mängder med bandbredd, detta för att sedan använda dem i ett nätverk av DDoS-botar. Detta gör att en DDoS-attack är näst intill omöjligt att spåra.&lt;/p&gt;

&lt;h3&gt;DRDoS &amp;ndash; Distributed Reflection Denial of Service&lt;/h3&gt;
&lt;p&gt;En &lt;abbr title="Distributed Reflection Denial of Service"&gt;DRDoS&lt;/abbr&gt;-attack är när &lt;strong&gt;en&lt;/strong&gt; eller &lt;strong&gt;flera&lt;/strong&gt; datorer utnyttjar en svaghet i en programvara eller ett protokoll för att förstärka effekten av en attack. Detta sker i kombination med att trafiken är &lt;a href="http://en.wikipedia.org/wiki/IP_address_spoofing" title="IP Spoofing" rel="external nofollow" target="_blank"&gt;spoofad&lt;/a&gt; så att det ser ut som att offrets dator är avsändaren.&lt;/p&gt;

&lt;p&gt;Två protokoll som utnyttjats mycket för detta ändamål är &lt;abbr title="Simple Network Management Protocol"&gt;SNMP&lt;/abbr&gt; och &lt;abbr title="Domain Name System"&gt;DNS&lt;/abbr&gt;, då de använder &lt;abbr title="User Datagram Protocol"&gt;UDP&lt;/abbr&gt; utan att verifiera avsändaren innan de svarar. Detta tillåter en angripare att skicka massor med förfrågningar från offrets IP-adress varpå dessa tjänster svarar (oftast med betydligt mer trafik än förfrågan i sig) till offrets dator.&lt;/p&gt;


&lt;h2&gt;Vad innehåller en överbelastningsattack?&lt;/h2&gt;
&lt;p&gt;Metoderna ovan beskriver generellt &lt;strong&gt;hur&lt;/strong&gt; en attack sker men inte &lt;strong&gt;vad&lt;/strong&gt; en attack består av. Det finns flera olika typer av överbelastningsattacker, alla som tjänar sitt syfte bäst.&lt;/p&gt;

&lt;h3&gt;TCP eller SYN-flood&lt;/h3&gt;
&lt;p&gt;Den vanligaste typen av attack är en så kallad SYN-flood, där man skickar så många &lt;abbr title="Transmission Control Protocol"&gt;TCP&lt;/abbr&gt;-paket som möjligt med endast SYN-biten satt. Eftersom man inte är intresserad av svaret offrets dator skickar, så kan man utan problem spoofa trafiken från slumpmässigt valda IP-adresser. Detta får offrets system att allokera mängder med halv-öppna anslutningar som gör att vanlig trafik nekas då det inte finns några lediga resurser att hantera detta.&lt;/p&gt;

&lt;h3&gt;UDP eller ICMP flood&lt;/h3&gt;
&lt;p&gt;Denna attack används oftast med syfte att förbruka så mycket bandbredd som möjligt. Eftersom både &lt;abbr title="User Datagram Protocol"&gt;UDP&lt;/abbr&gt; och &lt;abbr title="Internet Control Message Protocol"&gt;ICMP&lt;/abbr&gt; är stateless och inte kräver någon anslutning innan data skickas, så är det enkelt att skicka väldigt stor mängd data. Vanligast är att man skickar &lt;em&gt;ping&lt;/em&gt;-paket med hopp om att kunna förstärka attacken då offrets system svarar med ett &lt;em&gt;pong&lt;/em&gt;-paket.&lt;/p&gt;

&lt;h3&gt;Smurf och Fraggle&lt;/h3&gt;
&lt;p&gt;Dessa två attacker utnyttjar &lt;em&gt;broadcast&lt;/em&gt;-adressen genom att skicka &lt;em&gt;ping&lt;/em&gt;-paket som ser ut att komma från offrets dator. Detta gör att övriga datorer på nätverket svarar med &lt;em&gt;pong&lt;/em&gt;-paket. Dessa attacker fungerar sällan idag, då alla moderna system ignorerar &lt;em&gt;ping&lt;/em&gt; till &lt;em&gt;broadcast&lt;/em&gt;-adressen.&lt;/p&gt;

&lt;h3&gt;Teardrop, Ping of Death och Nuke&lt;/h3&gt;
&lt;p&gt;Teardrop utnyttjar en svaghet i TCP/IP-stacken på offret system. Teardrop innebär att man skickar fragmenterade paket som överlappar varandra, vilket äldre operativsystem inte klarade av att hantera utan krashade. Ping of Death och Nuke utnyttjade även de TCP/IP-stacken, då äldre operativsystem inte kunde hantera paket som var större än 64KB.&lt;/p&gt;


&lt;h2&gt;Avslut&lt;/h2&gt;
&lt;p&gt;Den andra delen i denna artikelserie kommer handla mer om hur du kan minska effekten av dessa attacker och hur du använder &lt;em&gt;iptables&lt;/em&gt; för att konfigurera brandväggen i Linux.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/krid_cPiJ_s" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/overbelastningsattacker-1</feedburner:origLink></entry>
  <entry>
    <id>http://www.ifconfig.se/youtube-mp3</id>
    <published>2010-12-13T08:09:00+01:00</published>
    <updated>2011-05-31T17:19:21+02:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/j2D_yqLFGg4/youtube-mp3" />
    <title>Från YouTube till mp3</title>
    <content type="html">&lt;p&gt;Visst har vi alla fått ett YouTube-klipp länkat till oss med ruggigt bra musik som soundtrack. Helst skulle man vilja ha musiken som en fil för att kunna spela den i sin favoritspelare. Detta är självklart möjligt med lite hjälp av diverse verktyg.&lt;/p&gt;

&lt;p&gt;För att först ladda hem filen från &lt;a href="http://www.youtube.com/" title="YouTube - Broadcast Yourself." rel="external nofollow" target="_blank"&gt;YouTube&lt;/a&gt; så kan du använda &lt;em&gt;&lt;a href="http://rg3.github.com/youtube-dl/" title="youtube-dl" rel="external nofollow" target="_blank"&gt;youtube-dl&lt;/a&gt;&lt;/em&gt;, vilket förmodligen finns tillgängligt via den pakethanterare din Linux-distribution erbjuder. Därefter använder vi oss utav &lt;em&gt;&lt;a href="http://www.ffmpeg.org/" title="FFmpeg" rel="external nofollow" target="_blank"&gt;FFmpeg&lt;/a&gt;&lt;/em&gt; för att hämta ut ljudspåret i filmen och spara om den som en mp3-fil.&lt;/p&gt;

&lt;pre class="brush: bash"&gt;youtube-dl http://www.youtube.com/watch?v=hKLpJtvzlEI
[youtube] Setting language
[youtube] hKLpJtvzlEI: Downloading video webpage
[youtube] hKLpJtvzlEI: Downloading video info webpage
[youtube] hKLpJtvzlEI: Extracting video information
[download] Destination: hKLpJtvzlEI.flv
[download] 100.0% of 7.79M at   34.77k/s ETA 00:00&lt;/pre&gt;

&lt;pre class="brush: bash"&gt;ffmpeg -y -i hKLpJtvzlEI.flv -ab 128k 'Clint Mansell - Lux Aeterna.mp3' 2&amp;gt;/dev/null&lt;/pre&gt;

&lt;p&gt;Nu kan du spela mp3-filen i valfri mediaspelare. :-)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/j2D_yqLFGg4" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/youtube-mp3</feedburner:origLink></entry>
  <entry>
    <id>http://www.ifconfig.se/identifiera-googlebot</id>
    <published>2010-12-12T12:55:00+01:00</published>
    <updated>2011-05-25T16:38:30+02:00</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ifconfig-se/~3/DKjt85KYBic/identifiera-googlebot" />
    <title>Identifiera en Googlebot</title>
    <content type="html">&lt;h2&gt;Analysera User-Agent (fel sätt)&lt;/h2&gt;
&lt;p&gt;Av diverse olika anledningar vill man ibland skilja på riktiga besökare och robotar, så som Googlebot, Slurp och Bingbot. Det absolut vanligaste sättet är att man analyserar besökarens &lt;em&gt;User-Agent&lt;/em&gt;-header och agerar olika beroende på om den innhåller t.ex Googlebot eller ej. Självklart ska man inte presentera olika innehåll för besökare eftersom man då riskerar att bli straffad för &lt;a href="http://www.google.com/support/webmasters/bin/answer.py?answer=66355" title="Läs mer om vad Cloaking är" target="_blank" rel="external nofollow"&gt;cloaking&lt;/a&gt;. Dock kan man ju agera olika internt, för saker som statistik eller liknande.&lt;/p&gt;

&lt;p&gt;Skrämmande nog har jag dock sett ett flertal forum som även listar privata delar av webbplatsen för en besökare som har ordet Googlebot i sin &lt;em&gt;User-Agent&lt;/em&gt;-header. Detta är inte rätt sätt att lösa det hela eftersom en besökare enkelt kan ändra sin &lt;em&gt;User-Agent&lt;/em&gt;-header.&lt;/p&gt;


&lt;h2&gt;Analysera besökarens IP-adress (rätt sätt)&lt;/h2&gt;
&lt;p&gt;Googlebot ansluter alltid från en adress som slutar på &lt;em&gt;*.googlebot.com&lt;/em&gt;. Denna adress pekar till en IP-adress som i sin tur pekar tillbaka till samma adress. Detta är värt att poängtera eftersom vem som helst som äger en IP-adress kan peka den till en &lt;em&gt;googlebot.com&lt;/em&gt;-adress och låtsas vara en Googlebot.&lt;/p&gt;

&lt;p&gt;Så för ta reda på om en besökare verkligen är en riktig Googlebot så börjar vi med att översätta IP-adressen till en host. Kontrollera att domänen för hosten är &lt;em&gt;googlebot.com&lt;/em&gt; och därefter översätta hosten till en IP-adress igen, för att verifiera att det är samma IP-adress som besökaren ansluter ifrån. Här är en simpel PHP-funktion för just detta:&lt;/p&gt;

&lt;pre class="brush: php"&gt;&amp;lt;?php

// is $ip really a Googlebot?
function is_googlebot($ip)
{
  // get the hostname
  $host = gethostbyaddr($ip);

  // if the hostname belongs to google, check for a reverse lookup.
  if (substr($host,-14) == '.googlebot.com' &amp;amp;&amp;amp; gethostbyname($host) == $ip)
    return true;
  else
    return false;
}

?&amp;gt;&lt;/pre&gt;&lt;br /&gt;


&lt;h2&gt;Yahoo! Slurp &amp;amp; Bingbot&lt;/h2&gt;
&lt;p&gt;Denna lösning fungerar även lika bra för Yahoo! Slurp och Bingbots robotar. Adresserna är uppbyggda på precis samma sätt och slutar på &lt;em&gt;*.crawl.yahoo.net&lt;/em&gt; respektive &lt;em&gt;*.search.msn.com&lt;/em&gt;. Notera dock att de har olika längd om du använder koden ovan.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ifconfig-se/~4/DKjt85KYBic" height="1" width="1"/&gt;</content>
    <author>
      <name>Jesper Wallin</name>
    </author>
  <feedburner:origLink>http://www.ifconfig.se/identifiera-googlebot</feedburner:origLink></entry>
</feed>

