Архива за 'Programming' категорију

MySQL Jokeri

април 11, 2008

Pitanje za milion dolara u nekom popularnom kvizu. Imate samo 15 sekundi za odgovor. Srecni ste jer ste izvukli pitanje iz vase omiljene oblasti :)

Kako obrisati sve korisnike ciji nick pocinje sa donjom crtom (’_').

I vas odgovor je naravno:

delete from users where username like '_%';

Vec mastate o raskalasnom zivotu daleko od kompjutera, mozda i neka jahtica pride (i sve sto ide u to lol). Glas voditelja vraca vas u surovu realnost. “Zao mi je, ovo nije tacan odgovor”. U neverici gledate vas query i milione koji su otisli u nepovrat.

Verovali ili ne, slicnu nevericu iskusio sam na svojoj kozi pre nekoliko veceri, tacnije 8. aprila. U tabeli sa nekoliko miliona generisanih domena uocen je bug (mala greska u regularnom izrazu) i nekako su generisani i domeni koji pocinju sa znakom “_”. Underscore (donja crta) naravno nije dozvoljen kod domena, bug je ispravljen ali treba obrisati i te nevalidne domene iz baze. Nista lakse, jedan brzi query i sve ce ubrzo biti pocisceno. Otvaram mysql klijent i bez mnogo razmisljanja kucam:

mysql> delete from result_domains where domain like '_%'; Query OK, 9035782 rows affected (9 min 57.35 sec)

WTF!?? Query je obrisao sve domene iz tabele. Ali kaaakooo???

I onda se setim. Donja crta - ‘_’ je poput ‘%’, takodje joker karakter koji za razliku od ‘%’ (koji menja ‘nula ili vise’ karaktera), ‘_’ menja tacno jedan karakter. Ne secam se kada sam ga poslednji put koristio (ako sam ga uopste koristio), ali znam da mi je on dosao glave.

Cimam admina na ICQ … treba mi backup, server taj i taj, tabela ta i ta, poslednji koji imamo … ASAP! Posle 30-tak sekundi admin se javlja “ok, poslednji koji imamo je od 8 marta. Gde da ti stavim?”. FUCK!!!

FUCK!!! FUCK!!! FUCK!!! FUUUUCK!!!

Ustajem od kompjutera i besno setam kroz sobu. Na postoji nacin da objasnim klijentu da sam jednim jedinim kverijem sjebao sate i sate mukotrpnog rada, podatke vredne verovatno hiljade dolara. Da imam utoku verovatno bih pao u iskusenje da pucam sebi u glavu. Mozda pre toga da sredim i admina? Kako god, sta je tu je, ne preostaje nista drugo nego da napisem email i objasnim svom klijentu sta se desilo.

Sedam ponovo za comp, ali umesto da otvorim thunderbird, cimam ponovo admina.

- Ja: “Jebote … kako se desilo da je poslednji backup star mesec dana???” - Admin: “Kako to mislis? Ovo je backup od sinoc!?” - Ja: “Rekao si 8 mart???” - Admin: “Ups. Sorry, 8. April. Sad gledam, kreiran je pre samo par sati. Moze?”

I tako, my ass has been saved. Ali moglo je i biti drugacije. Mnogo drugacije.

Pouka price:

1) Budite ekstremno oprezni kada kucate nesto unutar mysql klijenta (ili phpmyadmina) koji barata sa live podacima 2) Ako morate da brisete/update-ujete nesto, uvek uradite prvo count nad istim podacima i istom where klauzom kako bi ste se uverili da je to bas ono sto ste zeleli.

Npr:

mysql> select count(*) from result_domains where domain like '_%'; +----------+ | count(*) | +----------+ | 9035782 | +----------+ 1 row in set (5.27 sec)

(ups nesto ne valja, ovo ce obrisati sve domene koje imamo)

mysql> select count(*) from result_domains where domain like '\_%'; +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (4.18 sec)

Aha, sada je sve ok :)

3) Uvek pravite redovan backup. Ako to za vas rade admini postarajte se da rade svoj posao kako treba. Cak i tada nije losa ideja da s vremena na vreme napravite sopstveni backup.

P.S. Problem sa pocetka price (matchovanje stringa koji pocinje sa ‘_’) resava se jednostavnim escapovanjem specijalnog karaktera. Dakle:

select foo from footable where somefield like '\_%';

ili ako ste ljubitelj regularnih izraza:

select foo from footable where somefield regexp '^_';

Curl HTTP Client 1.2

фебруар 15, 2008

Upravo uploadovao novu verziju sa nekim sitnim izmenama. Ispravljeno je nekoliko sitnih bugova na koje su se korisnici žalili, a od novih mogućnosti dodata je mogućnost pozivanja send_post_data metoda direktno sa post stringom, zatim podrška za gzipped contents itd.

Verziju 1.2 možete skinuti ovde.

А какав си ти ђак, мали?

септембар 18, 2007

Сигурно су и вама старији постављали питање из наслова док сте били школарац. Ја сам увијек био одличан, па ми није сметало. Да сам у школи сада, опет ми вјероватно не би сметало. Али сада имамо и електронске дневнике, што зацијело убија дио шарма школовања. Вјероватно је нормално да клинац понешто не каже родитељима, са електронским дневницима он нема шта да говори, родитељи све већ знају. Велики Брат их посматра.

То ме подсјети на врло ефикасан метод мога оца, који би отишао ненајвљен и непозван у моју школу једном или два пута годишње, а да ја то нисам знао. А понекад би само дошао кући и рекао: Владане, молим те напиши ми које оцјене имаш. Наравно, то се дешавало чешће од тих један или два пута када је он стварно и ишао у школу, али будући да ја нисам знао када је то било стварно, углавном би све тачно рекао како стоје ствари. Но, увијек је било простора за мување :)

Али, ово није текст о мојим школским данима, већ о клинцима који тренутно иду у основне и средње школе, а у школама имају постављене електронске дневнике. Уопште не волим да коментаришем рад других колега из ИТ индустрије, али ово се тиче безбједности мале дјеце и мора бити наглашено. На страну што ми изглед страница не одаје осјећај сигурности и знања, оно што је за узбуну су данашње информације које говоре о томе да је у систем електронских дневника могуће релативно лако неовлаштено ући, како је писано на ДПТ форуму (уз слике као доказ). Ако систем при погрешно унесеним подацима лијепо опише грешку базе података, потребно је само мало маште да би сте ушли унутра. А унутра су приватни подаци малољетне дјеце. И таква врста неодговорности и даваоца услуге и Министарства просвјете ме заиста брине. И растужује…

belgrade, programming, security

PHP 4 end of life announcement

јул 14, 2007

Preuzeto sa php.net

[12-Jul-2007]

Today it is exactly three years ago since PHP 5 has been released. In those three years it has seen many improvements over PHP 4. PHP 5 is fast, stable & production-ready and as PHP 6 is on the way, PHP 4 will be discontinued.

The PHP development team hereby announces that support for PHP 4 will continue until the end of this year only. After 2007-12-31 there will be no more releases of PHP 4.4. We will continue to make critical security fixes available on a case-by-case basis until 2008-08-08. Please use the rest of this year to make your application suitable to run on PHP 5.

For documentation on migration for PHP 4 to PHP 5, we would like to point you to our migration guide. There is additional information available in the PHP 5.0 to PHP 5.1 and PHP 5.1 to PHP 5.2 migration guides as well.

Šta reći nego - Konačno! Nadam se da će ovo najzad pogurati ljude ka migraciji ka petici. A PHP6 samo što nije :)

Може ли сте покренути онлајн бизнис за један викенд?

јул 9, 2007

Прошлог викенда у Колораду, САД, одржана је једна занимљива акција, СтартапВикенд (StartupWeekend), у којој 70 људи покушава да за један викенд покрене један Wеб2.0 стартап. Од великог броја понуђених идеја (од јуна је трајало слање приједлога) изабрана је једна, Воснап (Vosnap), подршка групном доношењу одлука. Или просто, врста апликације за гласање са понуђеним одговорима, уз опцију позивања на гласање.Идеја скупа је занимљива и вјерујем да су учесници доста научили и лијепо се забавили. Учесници, њих 70 су истовремено и власници пројекта. Али, ово је све играрија… Нити је испитано тржиште, нити су ти људи икада радили заједно, нити је потребно да 70 људи ради на једном оваквом пројекту и на крају, што је мени посебно занимљиво - чак нису ни успјели. Наиме, рок да се лансира бета сајт је био недјеља увече, а у тренутку док ово пишем сајт и даље не ради.Могуће је да је ово смишљена ПР акција за промоцију стартап инкубатора чији оснивачи стоје иза акције.

Свеједно, и поред тога што нису успјели у задатом року, ја вјерујем да група људи који се добро познају у послу може створити овакво нешто за један викенд. Само, што је тако брзо, мора да је и кусо.

business, internet, programming, social, web2.0

Понешто о # знаку

јул 7, 2007

Појавом модернијих телефонских уређаја, а посебно рачунара, у свакодневну употребу се тихо увукао необичан знак #. Свакако ће они музички образовани примјетити да подсјећа на повисилицу, па га Грци, Французи, Румуни и Бугари зову тако, понекад и Американци (sharp), мада ови посљедњи много чешће користе ријечи pound и hash. Арапи и Данци га зову квадратом, Мађари двоструким крстом, Руси, Чеси и Словаци мрежицом, а Италијани капијицом и коначно Срби обично тарабом.

Очигледно, појаву овога знака у широј употреби није пратила и нека стандардизација, па отуд оволико шаренило назива. Тек касније, у Јуникод стандарду договорено је да званично име за знак # буде Number sign, што подсјећа на једну од употреба овога знака умјесто скраћенице No. при нумерисању. Овај знак није исто што и знак за музичку повисилицу и имају посебне стандардне ознаке и називе.

Мање познато име овога знака је октоторп (оctothorpe) или октатерп (octatherp) и сковано је у Беловим лабораторијама (Bell Labs) шездесетих година двадесетог вијека, када су стручњаци ове компаније радили на развоју тонског начина бирања за телефоне. Наиме, тада се указала потреба за увођењем два додатна тастера, звјездице * и тарабе #. Оба знака су и данас присутна на тастатурама телефона. Док за звјездицу није било пуно недоумица како је назвати (иако су изабрали ријеч star, а не asterisk), за именовање знака # су морали да укључе машту. Окто, први дио ријечи је позајмљен из грчког назива за број осам (као октопод, што ме подсјети на мени драг стари словенски назив за ову животињу - осминог, који и даље користе народи који више пазе на свој језик од нас), јер знак има осам кракова. За други дио ријечи не постоји сигуран извор о томе шта је. Свеједно, ово име, иако се сачувало, није никада ушло у ширу употребу.

Занимљива је била и расправа око назива овога знака у вријеме појаве новог Мајкрософтвог језика C#. Наиме, Мајкрософт је језик назвао Си-Шарп, као “повишени Ц”, али будући да на тастатурама не постоји знак за повисилицу, за ознаку језика су искористили сличан знак #, стварајући забуну да ли се језик зове Си-Шарп или Си-Хеш. Језик је стекао популарност и данас нема недоумица око његовог назива, али језичких недоумица са знаком # ће засигурно бити и даље. Само код програмера нема недоумица, погрешна употреба овога знака у већини програмских језика резултираће грешком :) А за шта се све користи овај знак погледајте на Википедији.

history, language, microsoft, programming

MySQL 5.x - Konačno unapređen klijent

јун 21, 2007

Listajući svoje omiljene WebDev feed-ove, za oko mi je zapao jedan post na sjajnom MySQL Perfomance Blogu:

…if you press CTRL-C MySQL Command Line Client will not exit but will terminate query being executed.

Drugim rečima, u dosadašnjim verzijama MySQL klijenta, kada bi ste ukucali neki query i pritiskom na CTRL-C pokušali da prekinete njegovo izvršavanje, CTRL-C bi zapravo ubio MySQL klijent, ali query nastavlja da se izvršava u pozadini! Rešenje u takvim slučajevima je traženje id-a tog query-a na listi procesa upitom “show full processlist”, a zatim njegovo “ubijanje” upitom “kill 12345″ gde je 12345 u ovom slučaju id procesa koji želimo da ubijemo. Dakle, recimo nešto ovako:

mysql> select * from odm_result_keywords where keyword like '%foo%joe%'; ^CAborted bash-2.05b$ mysql -A --enable-local-infile -udinke -ppass mydb Welcome to the MySQL monitor. Commands end with ; or g. Your MySQL connection id is 1512 to server version: 4.1.18-log Type 'help;' or 'h' for help. Type 'c' to clear the buffer. mysql> show full processlist; +------+-------+----------------------------+-------------------+---------+------+--------------+--------------------------------------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +------+-------+----------------------------+-------------------+---------+------+--------------+--------------------------------------------------------------------+ | 1486 | dinke | localhost | mydb | Query | 3 | Sending data | select * from odm_result_keywords where keyword like '%foo%joe.cl' | +------+-------+----------------------------+-------------------+---------+------+--------------+--------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> kill 1486; mysql>

Zahvaljujući izmenama u MySQL klijentu, sada je dovoljno da stisnete CTRL-C, i query će biti odmah prekinut:

mysql> select domain from odm_result_keywords_de where whois_status is null and domain like '%.%.%'; Query aborted by Ctrl+C ERROR 1317 (70100): Query execution was interrupted mysql>

Više informacija o ovoj, kao i drugim izmenama u pomenutoj verziji (5.0.25) možete naći ovde.

MySQL - Backup velikih MyISAM tabela

јун 20, 2007

Ako ste ikada morali da backup-ujete ili prebacujete podatke iz jedne ili više MySQL tabela, znate da se za to koristi mysqldump utility, pomoću kojeg jednostavno podatke iz MySQL-a “dumpujete” u neki mojetabele.sql fajl, koji zatim možete sačuvati kao backup, prebaciti i importovati na neki drugi MySQL server, itd. Ovu proceduru koristio sam milion puta do sada, i ona se generalno svodi na izvršavanje sledećih komandi u linuxu:

export:

mysqldump -udinke -pmojpass -hhostname.prvog.servera ime_baze tabela1 tabela 2 tabelan > dump_fajl.sql

import:

mysql -udinke -pmojpass -hhostname.drugog.servera ime_baze

Tu i tamo pojavi se problem kada prebacujete dump sa novije verzije MySQL-a na stariju, i tada je poželjno specifirati i odgovarajući compability flag prilikom izvršavanja mysqldump komande (–compatible=name gde name može biti mysql323, mysql40, postgresql, oracle itd.).

Elem, pre nekoliko dana zbog prebacivanja MySQL servera sa jedne lokacije na drugu, morao sam da odradim dump solidno velikih MySQL tabela (10-tak tabela gde je svaka imala preko 2 miliona slogova). Nakon užasavajuće duge procedure dumpa, gzipovanja i scpovanja na drugi server, konačno sam startovao import. Međutim, nakon 3 sata (tri sata) umesto standardne “no news is a good news” poruke, kada sam bacio pogled na status dočekala me je sledeća poruka …:

[dinke@um-917 ~/public_html]$ mysql -udinke -p325ewfwt23rasf keyword_discovery

WTF? Prebacivao sam podatke sa starije verzije na noviju, što znali da import mora proći glatko! Ovo bi trebalo da znači da je MySQL negde nešto pobrljavio sa indexima, i umesto da čekam još 2 sata da se odradi check & repair, odlučujem se da napravim ponovo dump fajl, ovaj put sa ignore opcijom, kako bi svi inserti u dump fajlu bili “insert ignore” tako da u slučaju ovakve greške ne bi došlo do pucanja. Ne preterano pametno, ali podaci nisu extremno osetljivi i mogu da dozvolim luksuz da izgubim desetak slogova, ali ne i desetak sati za import!

Naravno, novi dump, zip, scp … to je traajalooo … toliko dugo da sam posle par sati nakon startovanja importa krenuo da mozgam sa administratorom (kuki) oko alternativnih rešenja. A rešenje je bilo jednostavno ali efikasno. Prekopirali smo sve MySQL data fajlove sa jednog servera na drugi (*.MYI, *.MYD i *.frm fajlove), a zatim odradili myisamchk kako bi sredili pomenute tabele, jer nismo smeli da spuštamo server prilikom backup-a što generalno može da znači dosta problema ako se na ovaj način backupuju fajlovi.

Sve u svemu, ova operacija prošla je jako brzo (najduže je trajalo kopiranje fajlova sa jednog hosta na drugi), i za manje od pola sata cela procedura bila je završena.

Zaključak do koga smo došli je da je kod velikih tabela dumpovanje praktično nepihvatljivo kao backup rešenje, i da se samim tim kao jedino rešenje nameće kopiranje MySQL data fajlova. Kod MyISAM tabela to nije nikakav problem, jer su one “platform safe”, tj. binarni fajl kreiran na jednoj platformi (recimo *.MYI fajl na linuxu) radiće bez ikakvih problema na drugoj platformi (recimo isti *.MYI fajl na Windowsu).

Posao za PHP Programere

април 25, 2007

Juče me je po ko zna koji put moj klijent iz USA pitao za neke nove programere, po zna koji put sam stavio oglase na DPT i ES, i po ko zna koji put sam dobio jednu lepu okruglu cifru CV-eva. Nula, nada, ništa. Inače, kada sam postavio oglas na DPT, moj prijatelj Bluesman mi je ironično rekao da “ako nađeš takvoga, ja mu plaćam pola plate”. Obavešten čovek, nema šta. Slično je prošao i b92.net u svom oglasu za administratora sajta, a detaljnije o tome piše Dejan Bizinger.

No, neću više da kukam kako u Srbiji nema dobrih programera (ili bar onih kojima treba posao). Rešio da testiram blogosferu i postavim ponudu na posao ovde, i tako testiram moć naših cenjenih agregatora srpsko-hrvatske blogosfere :).

Evo ponude:

Lampix u saradnji sa svojim USA partnerom First Beat Media potražuje iskusne Programere/Developere koji zadovoljavaju sledeće uslove:

Pozicija 1: PHP Programer

- Minimum 2 godine iskustva u radu sa PHP-om - Odlično poznavanje MySQL-a. Iskustvo u dizajnu i implementaciji baza podataka. - Poznavanje principa Objektno Orijentisanog programiranja. - Iskustvo u razvoju AJAX aplikacija je plus. - Poznavanje Linuxa je plus. - Komunikativnost, posvećenost poslu, timski rad, kreativnost. - Sposobnost da se ispoštuju rokovi. - Želja za stalnim usavršavanjem. - Tečan engleski - Fakultetska diploma je plus

Pozicija 2: PHP Network Programmer

- Poseduje minimum 2 godine iskustva u radu sa PHP-om - Odlično poznaje MySQL i ima iskustva u optimizaciji istog. - Poznaje principe Objektno Orijentisanog programiranja i zna da iste primeni u praksi. - Poznaje *nix (minimum u meri da moze sam da se uloguje u shell, edituje fajlove i sl.) - Poznaje regularne izraze - Ima iskustva u network programiranju, bilo koriscenjem socketa ili Curl-a. - Komunikativnost, posvećenost poslu, timski rad, kreativnost. - Sposobnost i odgovorost da se ispoštuju zadati rokovi. - Želju za stalnim usavršavanjem. - Tečan engleski - Fakultetska diploma je plus

Zadatak potencijalnog kandidata (ako takav postoji u ovoj zemlji) bio bi razvoj i unapredjenje postojecih CLI PHP skriptova koje se koriste za neku vrstu data mininga, gde je neophodno spiderovati odredjene sajtove i pritom raditi bindovanje na vise adresa, multithreading (tacnije multiplexing) itd. Zbog kolicine podataka neophodno je i da se odlicno snalazi sa (relativno) velikim tabelama (par desetina miliona slogova) i optimizacijom istih.

U slučaju da zadovoljavate gornje uslove, molim vas pošaljite Vaš CV na email jobs@lampix.net (Nepotpune i neozbiljne prijave neće biti uzete u razmatranje).

Odabranim kandidatima biće ponuđen stalan posao uz atraktivnu platu i odlične radne uslove. Prednost imaju kandidati koji mogu da rade puno radno vreme u Lampix office-u u Kragujevcu, ali je za kvalitetne kandidate sa stalnom Internet konekcijom moguć rad i od kuće.

Inače, radi se o poslu koji se kao što rekoh može raditi i od kuće (ne živim u iluziji da će pojaviti neko iz Kragujevca), uz odličnu platu i nadasve opuštenu atmosferu. U slučaju da zadovoljavate gornje uslove i pritom želite da postanete deo ovog jakog multinacionalnog “creme de la creme” tima, šta čekate?

Client size resizovanje slika

март 12, 2007

Radeći na servisu Blogodak, nedavno sam se susreo sa problemom kod slika velikih dimenzija koje neki korisnici uključuju u svojim feedovima. Naime, kako Blogodak “vuče” feed-ove sa raznih domaćih blogova, a sa njima i slike koje se u njima nalaze, dešavalo se da one dimenzija većih od 560px uredno “skrljaju” layout blogotka, obzirom da to e == “Microsoft Internet Explorer”) {prevazilazi predviđenu veličinu containera, tako da u najboljem slučaju dolazi do pojave horizonatalnog skrol bara. Kako nemamo nikakav uticaj na slike koje se vuku sa servera gde su hostovane, server side varijante(npr. resize korišćenjem GD liba ili Image Magicka) nisu primenjive, jedino rešenje je da se dimenzije slike smanje direktno u browseru - Client Side.

CSS Rešenje Za browsere koji imaju potpunu podršku za css2, dovoljno je staviti nešto tipa:

.container img{ max-width:560px; }

u stil strane, tako da će sve slike koje se nalaze unutar nekog <div id=”container”>…</div> elementa biti ograničene na max 560 piksela, tj. biće automatski resizovane na odgovarajuću veličinu. Naravno, ovo ne radi u IE-u (verzije

IE Hack (CSS verzija)

.container img{ max-width:560px; /*hack for IE*/ width: expression(this.width > 560 ? 560: true); }

Ovaj css hack je validan samo u IE-u, koristi se neka vrsta “ternarnog operatora”, a sam hack skinut je sa ovog bloga. Rado bih vam rekao da više informacija potražite tamo, ali i sam autor priznaje da na razume mnogo oko toga “kako to radi”, ali jednostavno radi. Za ljubitelje standardnijih rešenja, sledi JS verzija.

IE Hack (JS verzija)

Obzirom da mi se nije svidela ideja da koristim nevalidan css kod koji uz to i ne razumem u potpunosti(na stranu što je pravio i neke nekoegzistentne probleme sa IE-om za koji je i namenjen), odlučio sam se za JavaScript rešenje koje sledi.

function fixImages() { //fix images for ie only if(navigator.appName == "Microsoft Internet Explorer") { for(i=0; i<document.images.length; i++) { //if image is bigger than 560 if(document.images[i].width > 560) { imgRatio = document.images[i].width/document.images[i].height; document.images[i].width = 560; document.images[i].height = 560 / imgRatio; //hack neophodan da bi se uklonio skroler zbog prvobitne velicine slike //mainContent je ime div kontejnera koji drzi sadrzaj strane divid = document.getElementById('mainContent'); content = divid.innerHTML; divid.innerHTML = ''; divid.innerHTML = content; } } } }

Ova funkcija se poziva nakon učitavanja stane(onLoad). U slučaju da je u pitanju IE, proveravaju se dimenzije svih slika na strani(parsuje se niz document.images), i u slučaju da dimenzije prevazilaze 560 piksela, setuju se na manje, uz očuvanje proporcija slike. Naravno, ovaj metod ima manu, jer je neophodno da se sve slike prvo učitaju, pa tek onda dolazi do resizovanja. Kod IE-a i pored resizovanja slike na “prihvatljive” dimenzije, bilo je potrebno nekako mu i staviti do znanja da je došlo do promene dimenzija(samo resizovanje nije dovoljno da nestane horizontalni skroler), tako da je bilo neophodno ručno ili skriptabilno rezisovati i prozor browsera. Srećom posle manjeg “prčkanja” sa alternativama prošlo je i jednostavnije rešenje sa setovanjem kontejnera cele strane na prazan string i vraćanjem na prvobitno stanje korišćenjem innerHTML-a.

Nadam se da će ovo nekome biti od koristi :)

Curl HTTP Client - Update

март 1, 2007

Upravo sam postavio novu verziju svoje Curl_HTTP_Client klase. Nove mogućnosti uključuju file download/upload, korišćenje proxya itd.

Novu verziju možete skinuti sa PHP Classes kao i sa mog sajta - ovde. Opis svih mogućnosti možete naći ovde.

Kako Prepoznati Srbina

децембар 16, 2006

Sećate li se mog prijatelja Manu-a, amerikanca koji prati isključivo fudbal(i to ne američki) ?

Manu 15.12.20 20:34 usa stole a serb footballer Manu 15.12.20 20:35 http://chivas.usa.mlsnet.com/players/bio.jsp?team t120&player=kljestan_s&playerId=kle326299&statTyp =current dinke 15.12.20 20:35 Sacha Kljestan ? Serb ? Manu 15.12.20 20:36 lol Manu 15.12.20 20:36 you should know Manu 15.12.20 20:36 that is serb name Manu 15.12.20 20:36 that is not serb name Manu 15.12.20 20:36 that is serb name Manu 15.12.20 20:36 that is not serb name Manu 15.12.20 20:36 to be or not to be a serb Manu 15.12.20 20:36 that is the question

Nakon što mi je sinoć po n-ti put(gde n–>00) servirao vest o nekom mom “zemljaku”, morao sam da potrošim vreme i objasnim mu kako da prepozna Srbina u vestima(tim pre što u našem multinacionalnom timu imamo dvocifren broj ovdašnjih programera):

function isSerb($lastname) { $found = preg_match("/^[\pL]+ić$/u", $lastname); if($found) { return true; } else { return false; } }

Uvod u GeoIP

новембар 27, 2006

Verovatno ste već bili u prilici da koristite Google Analytics alat, gde između ostalog možete na mapi sveta videti odakle tačno dolaze posetioci vašeg sajta, ili ste tu i tamo posetili sajt koji bi Vam između ostalog izbacio podatke o Vašoj trenutnoj lokaciji. Naravno, nije u pitanju nikakva magija, tačna lokacija posetioca definisana je na osnovu njegove IP adrese, a tehnologija koja se koristi prilikom “lociranja” korisnika opšte je poznata pod nazivom GeoIP.

Danas ćemo pričati o tome kako “locirati” posetioca pomoću PHP-a i Max Mind-ove GeoIP baze. U primerima koji slede koristicemo besplatne(lite) verzije GeoIP baza, obzirom da se za pune verzije plaća $50USD + $12USD za update (GeoIP Country baza) i $370USD + $90USD za update (GeoIP City baza). Mana lite verzija je što nisu uvek 100% ažurne, ali će odlično poslužiti za naš tutorijal, a iz ličnog iskustva tvrdim da su upotrebljive i u većini live projekata.

MaxMind obezbeđuje API za nekoliko popularnih programskih jezika, (kompletna lista dostupna je ovde), a detalji o PHP API-u dostupni su ovde. Pored takozvanog “Pure PHP API-a” koji ćemo ovde koristiti, postoje i PECL ektstenzija kao i apache modul(mod_geoip), koji pružaju bolje perfomanse ali i komplikovaniji setup.

Za početak neophodno je da skinete sve fajlove koji se nalaze na http://www.maxmind.com/download/geoip/api/php/ i snimite ih negde unutar vašeg Web stabla(recimo /htdocs/geoip). Za korišćenje GeoIP Country treba skinuti lite bazu odavde, a za city GeoLiteCity bazu odavde. Radi jednostavnosti korišćenja, obe baze ćemo takođe raspakovati u isti direktorijum gde smo i snimili fajlove iz PHP API-a (/htdocs/geoip).GeoIP Country ——————————–

Idemo sa primerom detekcije zemlje posetioca:

<?php /** * Primer Koriscenja GeoIP Country Baze * * @version $Id$ * @package geoip * @copyright © 2006 Lampix.net * @author Dragan Dinic <dinke@lampix.net> */ require_once("geoip.inc"); $gi = geoip_open("GeoIP.dat", GEOIP_STANDARD); $ip = $_SERVER['REMOTE_ADDR']; //ako testirate u lokalu koristite ovaj ip radi testa //posto ce $_SERVER['SERVER_ADDR'] biti 127.0.0.1 //$ip = "89.216.226.174"; $country_name = geoip_country_name_by_addr($gi, $ip); $country_code = geoip_country_code_by_addr($gi, $ip); if($country_name) { echo "Zemlja iz koje nas posecujete je: $country_name <br />"; echo "Skracena Oznaka: $country_code <br />"; } else { echo "Nazalost, nismo bili u mogucnosti da vas lociramo."; } geoip_close($gi); ?>

Dakle, na početku uključujemo geoip.inc koji sadrži sve f-je potrebne za korišćenje GeoIP County baze, zatim kreiramo novu instancu GeoIP klase pomoću geoip_open f-je, i na kraju pozivamo odgovarajuće f-je (geoip_country_name_by_addr i geoip_country_code_by_addr) da bi smo dobili ime/kod zemlje u kojoj se nalazi ip adresa posetioca(u slučaju da testirate u lokalu nemojte koristiti $_SERVER[’REMOTE_ADDR’]).

Kao izlaz skripta, trebalo bi da dobijemo nešto poput:

Zemlja iz koje nas posecujete je: Serbia and Montenegro Skracena Oznaka: CS

F-je koje smo koristili da bi dobili podatke o zemlji posetioca, samo su neke od f-ja koje su dostupne u API-u. Ostatak možete i sami pronaći jednostavnom analizom PHP sourca geoip.inc fajla.

GeoIP City —————————-

A sada da proširimo podatke o zemlji sa tačnom lokacijom (grad, poštanski kod itd).

<?php /** * Primer Koriscenja GeoIP City Baze * * @version $Id$ * @package geoip * @copyright © 2006 Lampix.net * @author Dragan Dinic <dinke@lampix.net> */ require_once("geoipcity.inc"); $gi = geoip_open("GeoLiteCity.dat", GEOIP_STANDARD); $ip = $_SERVER['REMOTE_ADDR']; //ako testirate u lokalu koristite ovaj ip radi testa //posto ce $_SERVER['SERVER_ADDR'] biti 127.0.0.1 //$ip = "89.216.226.174"; $record = geoip_record_by_addr($gi, $ip); if(!$record) { echo "Nazalost, nismo bili u mogucnosti da vas lociramo."; } else { echo "Zemlja: " .$record->country_name . "<br />"; echo "Skracena Oznaka: " . $record->country_code . "<br />"; echo "Skracena Oznaka2: " . $record->country_code3 . "<br />"; echo "Region: " .$record->region . "<br />"; echo "Grad: " .$record->city . "<br />"; echo "Postanski Kod: " .$record->postal_code . "<br />"; echo "Geog. Sirina: " .$record->latitude . "<br />"; echo "Geog. Duzina: " .$record->longitude . "<br />"; } geoip_close($gi); ?>

Kao što vidite, PHP kod je sličan kodu za detekciju zemlje, s tim što smo koristili geoipcity.inc kao i GeoLiteCity.dat bazu. F-ja geoip_record_by_addr($gi, $ip) vraća instancu klase ‘geoiprecord’ koja sadrži kao promenljive(osobine) podatke o lokaciji koje koristimo u gornjem kodu. Nakon pokretanja skripta trebalo bi da dobijemo nešto poput:

Zemlja: Serbia and Montenegro Skracena Oznaka: CS Skracena Oznaka2: SCG Region: 02 Grad: Beograd Postanski Kod: Geog. Sirina: 44.8186 Geog. Duzina: 20.4681

Napominjem da je GeoIP baza najažurnija kada su u pitanju gradovi sa severnoameričkog dela planete, dok je njena preciznost znatno manja kada se dođe do “egzotike” u koju nažalost spada i Srbija.

CaseStudy - Redirekcija na osnovu IP adrese ——————————————– Za kraj znanje stečeno ovde iskoristićemo u jednom pravom projektu. Naime cilj je da se na dvojezičnom sajtu(blogu) korisnici koji dolaze iz Srbije usmere na srpsku verziju sajta, dok će se svi ostali usmeriti na englesku verziju. Evo kako to izgleda:

<?php /** * Case Study - Redirekcija na osnovu lokacije * * @version $Id$ * @package geoip * @copyright © 2006 Lampix.net * @author Dragan Dinic <dinke@lampix.net> */ require_once("geoip/geoip.inc"); $gi = geoip_open("geoip/GeoIP.dat",GEOIP_STANDARD); $country_code = geoip_country_code_by_addr($gi, $_SERVER['REMOTE_ADDR']); geoip_close($gi); if($country_code == 'CS') { header("HTTP/1.1 301 Moved Permanently"); header('Location: http://www.dinke.net/blog/sr/'); } else { header("HTTP/1.1 301 Moved Permanently"); header('Location: http://www.dinke.net/blog/en/'); } ?>

Primer koji vidite gore koristi se upravo na ovom blogu, kako bi sve korisnike koji ne dolaze iz Srbije automatski preusmerio na englesku verziju bloga. Slanje custom 301 redirection headera je važno kako bi botovi (Google i sl.) indeksirali strane na odgovarajući način.

Izašao PHP 5.2.0

новембар 3, 2006

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

септембар 21, 2006

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.

Python 2.5

септембар 19, 2006

I just went over to the Python website to check out in more depth the new features of Python 2.5 when I got a sweet surprise – Python 2.5 FINAL is out!

You can download it here, read the highlights and of course what’s new.

Enjoy!

Curl HTTP Client

септембар 12, 2006

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 koristio sam sopstvenu HTTP klasu baziranu na soketima, 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 dabagovanje), ali mi se nikada nije preterano sviđao njegov PHP API, način na koji se setuje 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 mi čak slali 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) se mpže 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); ?>

IronPython version one

септембар 7, 2006

Finally, the beast is released – the long anticipated IronPython version 1.0 is out!

You can view the Release Notes and also the differences between IronPython 1.0 and CPython 2.4.3 – it’s definitelly a handy read.

I can’t wait to get my hands on it and experiment. Yee!

MySQL Workbench

март 16, 2006

Najbolji Open Source alat za dizajn baza i modelovanje DB Designer uskoro će dobiti naslednika u vidu programa MySQL Workbench .

MySQL Workbench je trenutno u beta fazi, ali već sada podržava nove mogućnosti MySQL-a 5 (trigeri, pogledi, stored procedure) kao i sve stare mogućnosti DBDesigner-a. Video (flash) demonstraciju mogućnosti MySQL Worknebch-a možete naći ovde.

Stigle knjizice

фебруар 28, 2006

Da vam malo pravim zazubice :)

MySQL Full-Text Searches

јануар 20, 2006
Danas vam predstavljam treći, ujedno i poslednji zapis iz serije tutorijala o "Mogućnostima MySQL-a koje developeri retko koriste". U prethodna dva pričali smo transakcijama i referencijalnom integritetu - mogućnostima 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 već) i došao je red na pretragu. Bez mnogo razmišljanja, dolazite do uobičajenog 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 uključiti više polja u pretragu, par logičkih operatora koje dinamički generišete u vašem scriptu i to je to? Hmmm ne baš.

MySQL::Spoljni Ključevi i Referencijalni Integritet

јануар 15, 2006
Danas nastavljamo sa započetom serijom tutorijala o retko korišćenim mogućnostima MySQL-a. U prošlom zapisu detaljno sam predstavio kako se u MySQL-u koriste transakcije. Danas ćemo se usresrediti na korišćenje "Spoljnih Ključeva i Referencijalnog Integriteta". Kao i kod transakcija, podrška za referencijalni integritet nije dostupna u standardnim MyISAM tabelama, već se moraju koristiti InnoDB tabele. Malo developera zna da je ova mogućnost dostupna još od verzije 3.23.44, koja se pojavila sada već davne 2001 godine. Za početak idemo malo sa teorijom, a posle ćemo preći na praktične primere.

MySQL i Transakcije

јануар 10, 2006
Kao što sam u prvom ovogodišnjem zapisu i najavio, od danas krećem sa serijom tutorijala o retko korišćenim mogućnostima MySQL-a kao što su transakcije, referencijalni integritet, fulltext search itd. Developeri ove mogućnosti MySQL-a retko koriste. Mnogi od njih čak i ne znaju da one postoje, pa se uobičajeno, bez puno argumenata, na raznim advocacy raspravama MySQL naziva nekompletnom bazom jer "ne podržava" ništa od gore navedenih mogućnosti. Malo ljudi zna da MySQL recimo podržava transakcije još od verzije 3.23.15 (izašla još maja sada već davne 2000-te godine). Slična je priča i sa ostalim mogućnostima. Ovaj tekst kao i nastavci koji slede ima za cilj da razbije neke predrasude o MySQL-u kao i da podstakne developere da počnu sa korišćenjem naprednijih mogućnosti koje im njihova baza pruža. Danas krećemo sa opisom transakcija.

MySQL - Prebacivanja tabele iz jedne baze u drugu

децембар 27, 2005
Pre neko veče sam morao da prebacim nekoliko tabela iz jedne baze (na istom MySQL serveru) u drugu. Pošto nisam imao vremena da se smaram sa dump-om, posle kraćeg razmišljanja došao sam do sledećeg rešenja:use prvabaza; create table foo like drugabaza.foo; insert into foo select * from drugabaza.foo; gde je prvabaza baza u koju prebacujemo tabele iz drugebaze. create table like ... kreira tabelu identično originalnoj uključujući i indexe, a drugi iskaz kopira podatke iz jedne u drugu. I tako za svaku tabelu posebno (srećom nije ih bilo mnogo). Danas sam listajući MySQL knjigu došao do znatno jednostavnijeg rešenja :)alter table drugabaza.foo rename prvabaza.foo; Jednostavno, brzo, efektno! Nadam se da će nekome ovo koristiti.