Izašao PHP 5.2.0

Nova verzija PHP-a, 5.2.0 od juče je dostupna za download.

Pored gomile ispravljenih bagova, nova verzija donosi i neke interesantne mogućnosti od kojih su meni najinteresantnije podrška za “progres bar” prilikom uploada, kao i podrška za zip fajlove. Više informacija o tome šta nam novo donosi PHP 5.2 možete pronaći ovde.

MySQL - Kako ukloniti duplikate

Ovaj post je donekle inspirisan problemom koji je bluesman opisao na svom blogu. Dva problema koji nemaju veze jedan sa drugim, ali odlično pokazuju zašto poslodavci insistiraju na x godina iskustva (gde x > 2) :)

Naime, danas sam “u minut do dvanaest” dobio fajl sa par stotina hiljada keyworda koje treba procesirati ASAP (oh kako volim ovu reč). Naravno, u žurbi nisam mnogo gledao u fajl, provalio sam da je format uobičajen (1 keyword po liniji), importovao u bazu sa load data local infile … , startovao procesiranje i to bi bilo to.

Par minuta nakon toga startuje me kolega koji je zaboravio da mi kaže da se kod nekih keyworda “potkralo” par domena tipa “foo.eu” gde ono “.eu” samo treba izbaciti. Sve je to lepo, ali svi su već importovani u tabelu i samo što nisu pokupljeni. Rešen da brzo delam, odlučim da je najjednostavnije odraditi “search/replace hack” direktno u tabeli, ali …

mysql> update odm_master_keywords
       set keyword = replace(keyword, '.eu','');
ERROR 1062 (23000): Duplicate entry 'academia' for key 2

Shit. Posto je keyword polje unique, neki od tih “.eu” je nakon search/replace-a napravio problem sa istim identičnim keywordom. Ok, obrisaću ručno te duplikate, valjda ih nema mnogo …

mysql> delete from odm_master_keywords_cl where keyword='academia';
Query OK, 1 row affected (0.02 sec)

mysql> update odm_master_keywords set keyword = replace(keyword, '.eu','');
ERROR 1062 (23000): Duplicate entry 'academic' for key 2
mysql> delete from odm_master_keywords_cl where keyword='academic';
Query OK, 1 row affected (0.02 sec)

mysql> update odm_master_keywords set keyword = replace(keyword, '.eu','');
ERROR 1062 (23000): Duplicate entry 'actriz' for key 2
mysql> delete from odm_master_keywords where keyword='actriz';
Query OK, 1 row affected (0.02 sec)

mysql> update odm_master_keywords set keyword = replace(keyword, '.eu','');
ERROR 1062 (23000): Duplicate entry 'foo' for key 2
mysql> delete from odm_master_keywords where keyword='foo';
Query OK, 1 row affected (0.48 sec)
...

I tako, mogao bih ovako do prekosutra … Mora da postoji nešto pametnije :)

Nakon kraćeg razmišljanja, došao sam do ovog rešenja. Privremeno skloniti “unique” index, odraditi update i vratiti index natrag, ali sa ignore opcijom koja će “ubiti” višak duplikata. Dakle:

mysql> alter table odm_master_keywords drop key keyword;
Query OK, 338565 rows affected (13.79 sec)
Records: 338565  Duplicates: 0  Warnings: 0

mysql> update odm_master_keywords set keyword = replace(keyword, '.eu','');
Query OK, 378 rows affected (4.95 sec)
Rows matched: 338565  Changed: 378  Warnings: 0

mysql> alter ignore table odm_master_keywords add unique keyword(keyword);
Query OK, 338565 rows affected (46.45 sec)
Records: 338565  Duplicates: 233  Warnings: 0

Obratite pažnju na ignore deo u poslednjem alteru. On je ključan ovde, jer da ga nismo koristili ponovo bi došlo do greške(duplicate entry …) prilikom update-a.

Inače, poslednja dva query-a su uobičajen “pattern” kada se želite osloboditi duplikata u nekom polju - jednostavno dodajte unique index na polje i višak će biti obrisan iz tabele.

Curl HTTP Client

Vrlo često u svojim svakodnevnim poslovima imam potrebu da parsujem podatke sa raznih sajtova (tipa lista expired domena, lista blogova na planetoidu i sl.) i to najčešće tamo gde nemam RSS na raspolaganju. Dugo vremena sam za takve zadatke koristio sopstvenu HTTP klasu baziranu na socketima, ali nisam nešto preterano bio zadovoljan perfomansama, plus sam bio suočen sa gomilom drugih problema tipa kompatibilnost između linuxa i bsd-a i sl.

U međuvremenu sam tu i tamo koristio Curl cli program (uglavnom za dibagovanje), ali mi se nikada nije preterano sviđao njegov PHP API, način na koji se setuju opcije i sl. Zbog svega gore navedenog, napravio sam sopstveni curl “oop wrapper” - jednostavnu klasu koja bi trebala da znatno olakša uobičajene zadatke kao što su slanje GET/POST zahteva, snimanje kukija i sl.

Obzirom da je još nekoliko kolega ovu klasu smatralo vrlo korisnom (neki su čak implementirali i dodatne mogućnosti), pre nekoliko nedelja odlučio sam da je submitujem na phpclasses.org kao Open Source projekat (BSD Licenca).

Evo nekoliko primera korišćenja. Klasa (kao i fajl sa primerima) može se downloadovati ovde.

<?php
/**
 * @version $Id$
 * @package dinke.net
 * @copyright © 2005 Dinke.net
 * @author Dragan Dinic
 */

require_once("curl_http_client.php");

$curl = &new Curl_HTTP_Client();

//pretend to be IE6 on windows
$useragent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";
$curl->set_user_agent($useragent);

//uncomment next two lines if you want to manage cookies
//$cookies_file = "/tmp/cookies.txt";
//$curl->store_cookies($cookies_file);

//Uncomment next line if you want to set credentials
//$curl->set_credentials($username, $password);

//Uncomment next line if you want to set specific referrer
//$curl->set_referrer("http://my.referrer.url");

//if you want to send some post data
//form post data array like this one
$post_data = array('login' => 'pera', 'password' => 'joe', 'other_foo_field' => 'foo_value');
//and send request to http://www.foo.com/login.php. Result page is stored in $html_data string
$html_data = $curl->send_post_data("http://www.foo.com/login.php", $post_data);

//You can also fetch data from somewhere using get method!
//Fetch html from url
$html_data = $curl->fetch_url("http://www.foo.com/foobar.php?login=pera&password=joe&other_foo_field=foo_value");

//if you have more than one IP on your server,
//you can also bind to specific IP address like ...
//$bind_ip = "192.168.0.1";
//$curl->fetch_url("http://www.foo.com/login.php", $bind_ip);
//$html_data = $curl->send_post_data("http://www.foo.com/login.php", $post_data, $bind_ip);
?>

Stigle knjizice

Da vam malo pravim zazubice :)

MySQL Full-Text Searches

Danas vam predstavljam treci, ujedno i poslednji zapis iz serije tutorijala o “Mogucnostima MySQL-a koje developeri retko koriste”.

U prethodna dva pricali smo transakcijama i referencijalnom integritetu - mogucnostima koje su dostupne samo u InnoDB i BDB tabelama. Danas vam predstavljam “Full-Text Search”, koji je za razliku od gore opisanih feature-a dostupan samo u MyISAM tabelama (što je MySQL-ov default).

Upravo ste kreirali još jedan database driven sajt (Forum, Blog, CMS, šta vec) i došao je red na pretragu. Bez mnogo razmišljanja, dolazite do uobicajenog rešenja:

select * from moja_tabela
where textpolje like '%text_iz_search_polja%'

koje po svoj prilici završava posao. Malo varijacije na temu ako je potrebno ukljuciti više polja u pretragu, par logickih operatora koje dinamicki generišete u vašem scriptu i to je to? Hmmm ne baš.

(more…)

« Previous Page Next Page »