Kebmans blogg

Hvordan gjøre ordsøk i MySQL

Posted in Programmering, Programvare, Scripting, Teknologi by kebman on 25/02/2012

Så du trenger å søke etter ord i databasen din? Her er noen kjappe eksempler på hvordan du kan gjøre det.

Fulltext-søking er kanskje den greieste måten å søke etter ord i SQL-databaser. Det er veldig kjapt og fungerer bra så lenge ordet er lenger enn tre bokstaver. Grunnen til dette er at det krever ekstra kapasitet å indeksere kortere ord, spesielt om de opptrer ofte. Slik bruker du fulltext-søk:

SELECT * FROM tabell
WHERE MATCH(felt)
AGAINST('søkeord' IN BOOLEAN MODE);

Men hva om du ønsker å søke etter ord med færre enn fire bokstaver? Vel, her er noen alternativer.

Ved å bruke LIKE kan du søke etter felter som inneholder ditt søkeord, enten det er del av større ord eller ikke. Du får som regel ganske mange treff med denne, og det er ikke like kjapt som Fulltext-søk.

SELECT * FROM tabell
WHERE felt
LIKE '%søkeord%';

Eksperimenter med å fjerne prosenttegn foran eller bak. Prosenttegnet fungerer som et «wildcard» eller en joker, og betyr «hvilken som helst tegn».

Men kanskje du bare vil ha hele ord som står alene? Prøv i så fall regular expressions.

SELECT * FROM tabell
WHERE felt
REGEXP '[[:<:]]søkeord[[:>:]]';

Merk at denne vil også gi treff på ord som har bindestrek foran eller bak. En annen hake er at regular expressions kan være litt tregt fordi det krever en del ekstra prosesseringskraft. Det er ikke alltid det er så viktig, men skal du lage noe som er stort og blir hyppig brukt av svært mange brukere, risikerer du fort at forsinkelsene blir merkbare.

Vil du kun ha helt enslige ord, må du søke etter ord som har mellomrom foran og bak. Prøv i så fall denne:

SELECT * FROM tabell
WHERE Locate('søkeord ', felt) > 0
AND Locate(' søkeord', felt) > 0;

Legende:

  • tabell: Databasetabellen du ønsker å søke i
  • felt: Feltet i tabellen som du ønsker å søke i
  • søkeord: Søkeordet du ønsker å bruke

PHP kobler ikke til MySQL via localhost

Posted in Internett, Programmering, Scripting, Teknologi, Webdesign by kebman on 24/02/2012

Fikk plutselig feil da jeg prøvde å koble til MySQL-databasen via PHP i dag. Vips så ble det en aldri så liten detektivhistorie.

Koden jeg bruker for å koble til MySQL med PHP er veldig enkel, godt testet, og har fungert mange ganger før. Ikke det mest avanserte og ikke objektorientert, men den egner seg godt for testing. Her er den:

$host = 'localhost';
$user = 'root';
$pass = 'password';
$link = mysql_connect($host, $user, $pass);
if (!$link) {
   die('MySQL error '. mysql_errno() . ': ' . mysql_error());
}

Kort forklart, hvis $link klarer å koble opp til databasen går alt som det skal, mens om variablen inneholder feil, blir koblingen brutt og det blir istedenfor sendt tilbake noen feilmeldinger. Og her er den jeg fikk:

MySQL error 2002: No such file or directory

Så jeg prøvde å bytte ute passord, bruker, og byttet fra localhost og til 127.0.0.1, og heureka! Da funket det. Men likevel var jeg jo like langt i forhold til localhost. Jeg blunket litt med de våte øynene mine, og et slags mørke la seg over hjernen min. Feilmeldingen sa meg ikke en dritt, og jeg skjønte ikke hvorfor det bare funket med den lokale IP-adressen. Her var det bare å sette i gang og google.

En av tingene jeg testet var om MySQL i det hele tatt reagerte, men det visste jeg jo at den gjorde, fordi jeg kunne koble til via terminalen og via Sequel Pro. Likevel prøvde jeg å pinge den over telnet i terminale, slik:

telnet localhost 3306

Her tittet MySQL frem og sa hei som normalt, så dette var i orden, og fortsatt var jeg like lite klok.

Heldigvis kom jeg ganske snart over denne fine siden: C.5.2.2. Can’t connect to [local] MySQL server

Der sto det utrolig mye unødvendig og irrelevant, men jeg bet meg i alle fall merke i de tingene som faktisk stemte – blant annet en serie tester man kan gjøre i terminalen, disse her:

  1. mysqladmin version
  2. mysqladmin variables
  3. mysqladmin -h `hostname` version variables
  4. mysqladmin -h `hostname` --port=3306 version
  5. mysqladmin -h host_ip version
  6. mysqladmin --protocol=SOCKET --socket=/tmp/mysql.sock version

Da jeg kom til nummer tre på listen, skjønte jeg at noe var galt. Det gikk helt fint om jeg byttet ut `hostname` med localhost, men da jeg brukte den riktige koden, `hostname`, fikk jeg en feilmelding:

mysqladmin: connect to server at 'kebman.local' failed
error: 'Host '10.0.0.7' is not allowed to connect to this MySQL server'

Dette skjønte jeg ikke noe særlig mer utav heller, men det ante meg at det kunne være at en eller annen trodde at kebman.local var localhost, men det er jo slett ikke tilfelle. Dessuten er jo ikke 10.0.0.7 adressen til localhost heller (127.0.0.1 er adressen til localhost).

Lenger nede i dokumentet sto det noe om å finne navnet på socket-filen som brukes for å koble via localhost:

netstat -ln | grep mysql

Svaret jeg fikk, var dette:

/tmp/mysql.sock

«Hm», tenkte jeg nå. «Kan dette ha noe med denne kebman.local-greia å gjøre, tro? Feilen må jo ligge i php.ini et sted (filen man bruker til å konfigrere PHP med), men hvor?» Hadde også lest noe om det på erværdige stackoverflow.com. Jeg søkte igjennom alt som hadde med MySQL i php.ini, og endelig fant jeg det. I php.ini var det en annen adresse til mysql.sock. Jeg endret det til adressen jeg fikk opp med netstat-koden, og voila, endelig funket det å koble til MySQL via localhost med PHP igjen.

For å redigere php.ini på Mac må du først ha rot-passordet til maskinen din. Deretter er det letteste å bruke TextWrangler (gratis) til å åpne opp /etc/php.ini for redigering. Du kan også åpne filen med pico eller et annet UNIX-program for tekstredigering gjennom sudo-kommandoen (sudo gir ordre som rot-bruker).

Function og array i PHP

Posted in Økonomi, Programmering, Scripting, Webdesign by kebman on 10/11/2010

#Ruter, selskapet med ansvar for kollektivtransporten i Oslo og Akershus, har for mange billettyper å velge imellom, of derfor kan det være svært vanskelig å vite hva slags billett som er den beste å ha til en hver tid. Som ledd i et personlig korstog for å lage en kalkulator som regner ut den beste billettypen for deg – fordi Ruter sannsynligvis ikke har noen planer om det -  har jeg lekt meg litt med funksjoner og listevariabler i PHP.

<?php
// Pris på enkelbilletter for voksne i Akershus
// Nøkkel: sone => pris
$enkelBillA_v = array(1=>30,2=>40,3=>50,4=>60,5=>70,6=>80,7=>90,8=>100,9=>110,10=>120);

// Funksjon som lager barnebilletter av voksenbilletter
// Opprett funksjonen og send prisene for voksenbilletter til den
function enkelBarneBillA($voksenbilletter) {

// Gjør barnebillettene lik voksenbilettene
$barnebilletter = $voksenbilletter;
// Men gå igjennom alle prisene til barnebilettene...
foreach ($barnebilletter as &$value) {

// ...og del dem i to - HEEE-YAHH!
$value = $value / 2;

}

// Returner svaret ut av funksjonen
return $barnebilletter;
}

// Enkelbiletter for barn i Akershus
$enkelBillA_b = enkelBarneBillA($enkelBillA_v);
// Arrayen er lik outputen av funksjonen enkelBarneBillA(),
// og til denne funksjonen sender vi prisene på alle voksenbillettene
?>

Og en stort vanskeligere måte å dele et tall i to på, skal du vel egentlig lete lenge etter… Men nå har du altså et lite eksempel på hvordan funksjoner kan brukes sammen med listevariabler. Du kan teste den nye variabelen ved å ta med følgende kode:

<?php print_r($enkelBillA_b); ?>

Heldigvis finnes det en litt enklere måte å gjøre det på:

<?php
// Funksjon som halverer det den får inn:
function halver(&$value) { $value = $value / 2; }
// Kopierer priser for voksenbilletter til $barnebill:
$barnebill = $enkelBillA_v;
// Spaserer igjennom $barnebill og halverer alle prisene:
array_walk(&$barnebill, 'halver');
// Helt sant, bare sjekk:
print_r($barnebill);
?>

Problem med dobbellagring av filer

Posted in Programmering, Programvare, Teknologi by kebman on 23/07/2010

For hvert uerstattelig bilde jeg tok, måtte det tas backup. Siden jeg ikke var så nøye med hvordan jeg gjorde det, har det endt opp i et bildekaos som bare tar mer og mer plass på harddiskene mine. Her er hvordan jeg er i ferd med å løse problemet.

Sjekk også Organisering: Nøkkelen til fotografisk lykke.

Jeg har lenge hatt proble med dobbellagring av filer, spesielt siden jeg driver med foto og jeg tar backup i hytt og pine. Dette har utviklet seg til et reelt problem som tar opp svært mye diskplass, uten at det er lett å gjøre noe med av redsel for å slette filer jeg egentlig har lyst å beholde. Løsningen er selvfølgelig programvare som finner duplikater og dobbellagrede filer, men det var lettere sagt enn gjort å finne.

Gjør det selv

Jeg har lett litt rundt, men ikke funnet noen produkter som gjør akkurat det jeg ønsker på en tilfredsstillende måte. Min kompis Lars Thomas sa at det ikke var noe problem for en kar som meg, og at jeg bare fikk skrive programmet selv. “Hehehehe” var alt jeg klarte å svare på det, men siden det nå tross alt er ferie tok jeg faktisk på meg utfordringen.

Siden jeg er i den heldige situasjon å jobbe på et UX-basert system* (Mac OS X) med Perl forhåndsinstallert, skriptingspråket som også kalles “The Swiss Army Chainsaw”, satte jeg i gang med det. Til nå har dette egentlig bare vært en glede å holde på med.

De nødvendige steg

Å komme frem til et program som presenterer dobbellagrede filer har mange mindre steg. Det aller første man må gjøre er å finne ut hvordan man åpner ei fil og sjekker innholdet. Så er det jo greit å kunne få ei liste over filene i ei mappe, for eksempel, slik at man kan åpen alle filene. Deretter må man finne ut hvordan man sammenligner disse på mest mulig effektiv måte.

Sjekk summen

Tilfeldigvis finnes det allerede små programmer som lager sjekksum (checksum) av filer, og forhåndssintstallert med de fleste UX-systemer er MD5. De er egentlig ment for å sjekke at en fil som ble sendt over nett ikke har blitt ødelagt på veien ved å lage en sjekksum utav fila. Er sjekksummen den samme som da den ble sendt, er ingenting forandret i filen. Samme teknikken kan brukes til å finne duplikater. Istedenfor at man prøver å sammenligne hele filer opp mot hverandre, som er upraktisk siden noen filer er svære, kan man bare sammenligne sjekksummen. Har man to filer med samme sjekksum, er sjansen stor for at det er dobbellagring ute og går.

Under er scriptet jeg har har fått til så langt. Alt du lurer på står kommentert i grått. Jada, vet det er overkommentert, men da lærer du lettere.

Perl-skriptet:

#!/usr/bin/perl
# Lager sjekksum av alle filene i en mappe, og printer dem til skjerm.

use strict;
use warnings;
use Digest::MD5 qw(md5_hex); # Importerer MD5 biblioteket. Tingen som gjør det mulig å lage sjekksum av filer.
use Cwd; # Dette biblioteket importeres for bedre kontroll over mappevisning.
#
# Håndtering av mapper:
#
opendir(DIR, "."); # Åpner mappen du er i.
# my @files = readdir(DIR); # lister opp ALLE filene, inkludert ./ og ../.
# my @files = grep(/\.$filetype$/,readdir(DIR)); # Mulighet for å lese kun filer av type $filetype. Kommentert ut. Variabelen $filetype må også deklareres om det skal funke siden vi bruker "strict".

my @files = grep( -f ,readdir(DIR)); # Lister opp alle filer, unntaken mapper og symbolske lenker. De sistnevnte forhindres av UNIX-kommandoen "grep -f", som du også kan kjøre fra terminalen, f.eks med en pipe når du bruker UNIX-kommandoen "ls" (samme som "dir" i DOS, altså å liste opp filene i en mappe).
closedir
(DIR); # God praksis.
# Deklarerer variabler siden vi bruker "strict":
my $file; # For øyeblikket tom, men vil bli fylt for hvert element i arrayen @file_liste ettersom den blir loopet igjennom.
my $pwd = &Cwd::cwd()."/"; # Får tak i den fulle statiske adressen (tråden/path) til mappen du er i. Ekvivalenten til UNIX-kommandoen "pwd".
#
# Håndtere sjekksummering av filer:
#
foreach $file (@files) { # Loop igjennom alle filene i nåværende mappe (directory).
   open(FILE, $file) or die "Får ikke åpnet '$file': $!"; # Åpne hver fil.
   binmode(FILE); # Åpne hver fil som binærdata.

   my $md5 = Digest::MD5->new; # Opprette en ny metode for sjekksummering av en fil, så lenge (while) slutten av datastrømmen enda ikke er nådd.
   while (<FILE>) {
      $md5->add($_);
   }
   close(FILE); # Alltid god praksis.
   print $md5->b64digest, " $pwd$file\n"; # Print MD5 sjekksum til skjerm for hver fil i arrayen @file_list.
}
Creative Commons License
Checksum Files in Dic by Kebman is licensed under a Creative Commons Attribution 3.0 Unported License.

Alt skriptet gjør til nå er å åpne mappen skript-filen ligger i, lese igjennom alle filene, lage en sjekksum av dem med MD5, og skrive resultatet til skjermen. Intet mer. Men i alle fall kan det brukes til å finne duplikater i samme mappe ved å inspisere sjekksummene.

Resultatet blir seende slik ut når du kjører det fra terminalen:

MacBook-Pro-usr:checksum_test usr$ perl Checksum_Files_in_Dic.pl
N03psjKibdP/7GV3itPLXw /Users/usr/dup_test/23.txt
tTE3ieMQOwLCyaRtWenETg /Users/usr/dup_test/24.txt
N03psjKibdP/7GV3itPLXw /Users/usr/dup_test/3 en.txt
c4kPP/IdNgVZcbwYN9HjeA /Users/usr/dup_test/4 en.txt
nF0fIWxHfWb5NPbytia0cg /Users/usr/dup_test/5.txt
N03psjKibdP/7GV3itPLXw /Users/usr/dup_test/99.data.txt

En bedre versjon ville istedenfor skrevet resultatene fra alle valgte mapper til en database, gjort en sammenligning der, og så kun printet eventuelle duplikater til skjerm. En liten database holder, som f.eks SQLite, som også allerede er installert på de fleste Mac-er.

Føl deg fri til å stjele Perl-koden min og bruke den som du måtte ønske. :) Den er CC-lisensiert for fri bruk av både private og kommersielle aktører.

* UX-basert system er et system basert på operativsystemet UNIX. Dette systemet har mange avarter. Mest kjent er kanskje Linux, men det gjelder også Mac OS X og mange flere.

Følg med

Få nye innlegg levert til din innboks.