ModRewrite: What a confusing thing!

Semalaman penuh aku dipusingkan karena selalu gagal dalam membuat rule untuk rewrite URL. Rule yang aku buat selalu gagal, padahal secara logic itu sudah bener.

Sebenarnya keinginan aku simpel. Internal redirect semua request selain ke directory /js, /img, /css dan /pub ke index.php?path=%URL%. Jika URL tidak di akhiri dengan / maka external redirect dengan URL yang sama tapi di akhiri dengan /. Ini karena aku ingin mengemulasikan bahwa request URL di anggap sebagai request ke folder kecuali jika request mempunyai pattern .*[\.].* (file like dan request ini tidak diperbolehkan).

Ketika pertama kali membuat rule dengan rewrite URL normal dari /home ke model /index.php?path=home semua berjalan baik termasuk rule allow directory khusus semua berjalan baik. Masalah timbul ketika mencoba membuat rule untuk emulasi request directory. Request untuk /home gagal diexternal redirect ke /home/ tetapi diexternal redirect ke /index.php/?path=index.php/&path=home

Penasaran kenapa bisa terjadi seperti ini, aku coba untuk melihat access.log milik Apache. Sungguh hal yang tak diduga, Apache menerima 3 request yang aneh:

127.0.0.1 - - [18/Aug/2007:01:59:29 +0700] "GET /FR/home HTTP/1.1" 302 370
127.0.0.1 - - [18/Aug/2007:01:59:29 +0700] "GET /FR/home/ HTTP/1.1" 302 390
127.0.0.1 - - [18/Aug/2007:01:59:29 +0700] "GET /FR/index.php/?path=index.php/&path=home HTTP/1.1" 200 155

Request pertama memang seperti yang aku inginkan, karena memang begitulan jika terjadi request pada directory. Tapi request yang kedua terjadi keanehan karena seharusnya ModRewrite mendeteksi URL model kedua adalah valid dah langsung di internal redirect tapi kok malah dilaporkan temporary moved.

Akhirnya aku harus tenggelam pada manual ModRewrite Apache (menyedihkan memang, karena aku tidak punya manual untuk ModRewrite penuh — menang ada gak ya? dunno!) dan voila… aku temukan bahwa ModRewrite punya logger… (wkwkwkw kenapa tidak mulai pertama aku temukan ini)

Dengan bantuan logger ini aku coba menyelam lebih dalam bagaimana ModRewrite menangani rule-rule yang aku buat dan aku temukan bahwa rule yang buat di handle tidak seperti bagaimana logic yang aku inginkan.

Ini rule yang aku definikan:

RewriteCond $1 =js [NC,OR]
RewriteCond $1 =img [NC,OR]
RewriteCond $1 =css [NC,OR]
RewriteCond $1 =pub [NC]
RewriteRule ^([^/]*) - [L]

RewriteRule ^.*[^/]$ ${REQUEST_URI}/ [L,R]

#RewriteRule ^(.*[^/])$ index.php?path=$1 [L,QSA]
RewriteRule ^(.*/)$ index.php?path=$1 [L,QSA]

Rule ke 3 dicomment karena seharusnya tidak ada lagi URL tanpa forwardslash karena jika ada akan diexternal redirectkan oleh rule ke 2.

Untuk lebih masuk kebagaimana yang aku inginkan terjadi, aku coba uraikan logic yang aku inginkan pada request /home

Pertama /home akan dibandingkan dengan rule nomor 1 dan pass it, rule ke 2 unpass karena /home tidak mempunyai postfix / dan harus diexternal redirect. Request hasil dari external redirect adalah /home/ dan ini akan pass rule 1 dan 2 tapi tidak untuk rule 4 (rule 3 dicomment out) sehingga hasilnya seperti yang aku inginkan.

Tapi ternyata tidak, mengapa? karena (setelah berjam-jam pusing dan berjam-jam pula melototin hasil log ModRewrite — ampun dah gitu aja butuh berjam-jam) ModRewrite tidak berjalan persis seperti logic yang aku inginkan.

ModRewrite ternyata menjalankan rule tersebut sekali lagi (tepatnya — mungkin akan — berkali-kali) setelah external redirect, sehingga ketika round pertama URL sukses diexternal redirect ke /home/ dan direwrite ke /index.php?path=home. Tapi pada round kedua URL ini unpass pada rule ke 2 karena memang pada query string tidak terdapat forwardslash sehingga diexternal redirect lagi dengan bantuk /index.php/?path=index.php/&path=home. What a wierd… (or its me that too wierd — wkwkwkwk).

Dan pada request ketiga baru URL benar karena rule 1, 2 semuanya pass tapi rule 4 membarikan hasil yang aneh (tapi benar secara ModRewrite) yaitu /index.php/?path=index.php/&path=home. Path yang kedua adalah hasil dari rewrite pertama ketika request diexternal redirect untuk pertama kali.

What a f**k… Woke, akhirnya (penjang sebenarnya karena setelah berjam-jam aku coba untuk mencari cara yang efektif dan baik — menurutku) aku ubah rule menjadi:

RewriteEngine on

# set to base rule
RewriteBase /FR/

# pass if query was correct ie. /index.php?path=home
RewriteCond %{QUERY_STRING} path= [NC]
RewriteRule ^index.php$ - [L]

# request was / or /index.php
RewriteCond %{QUERY_STRING} !path= [NC]
RewriteCond $1 ^index.php$ [OR]
RewriteCond $1 ^$
RewriteRule (.*) index.php?path= [L,QSA]

# allow direct request pada url yang diawali /js, /img, /css dan /pub
RewriteCond $1 js [NC,OR]
RewriteCond $1 img [NC,OR]
RewriteCond $1 css [NC,OR]
RewriteCond $1 pub [NC]
RewriteRule ^([^/]*) - [L]

# report object is missing if request is a file
RewriteRule ^(.*\..*)$ - [L,R=404]

# redirect if request is not a valid path model
RewriteCond %{REQUEST_URI} ^.*[^/]$
RewriteRule ^(.+)$ %{REQUEST_URI}/ [L,R,NS]

# rewrite to corrent one. ie. /home/ to /index.php?path=home
RewriteRule (.*) index.php?path=$1 [L,QSA]

Rule ini membarikan apa yang aku inginkan, rule ini akan memperbolehkan request dalam bentuk apapun selama request diawali dengan /js, /img, /css dan /pub (rule 3), melarang request pattern file selain /index.php (rule 1, 2, 3, 4), mengexternal redirectkan request path non postfix forwardslashed seperti /home ke /home (emulasi request folder, rule 5) dan merewrite semua request valid ke bentuk /index.php?path={REQUEST_PATH} (rule 6).

Tapi sayang rule ini masih belum bisa menangani bahwa request /index.php hanya boleh via rewrite URL (rule 2 dan 6), mungkin lain waktu aku akan begadang untuk mencari penyelesainnya.

Oke, cukup disini petualangan dari ModRewrite. Sudah semalaman begadang gara-gara INTERNAL REDIRECT — begitu log ModRewrite menyebutkan ketika rule di jalankan untuk round ke 2 karena URL direwrite ulang — sekarang udah pagi, jam 5.14 AM — aku mulai membuat rule jam 22 PM -an dengan menelantarkan perkerjaan wajib aku (sedih… banget).

Betapa bodoh aku!

Lusa, aku convert salah satu class untuk menggunakan query, sebelumnya class itu menggunakan wrapper untuk mendapatkan data. Convert selesai, ketika dicoba terjadi kesalahan. Data tidak keluar. Dicek semuanya ok, query seperti yang direncanakan. Tapi kok….

Setelah telusur punya telusur ternyata aku kurang menambahkan “,” pada query. Ok… aku mengakuinya, aku kurang teliti…. Query awal berjalan dengan baik…

Query kedua… Gagal… loh? knapa lagi dengan query ini…. dicek semua ok, tapi …. oh my god! kurang “,” lagi…. berikutnya… sama… yang lain kurang “and”. Wadoww….. knapa seh aku…

Busuk!!!!! kok bisa seh aku lupa kasih “,”, “and” dan sebagainya…. akibat dari itu aku kehilangan jam-jam coding aku hanya untuk mencari kesalahan query itu. Mencarinya juga gak semudah membalik tangan. Karena hasil query di ubah ke JSON dan dikirim ke client jadi pesan kesalahan query diabaikan, dan memberikan silent error…. sial…

Point yang ingin aku tekankan adalah, aku udah berulang-ulang kali buat query, masak gak tau kalo query itu kurang “,” atau “where”-nya kurang “and” sebagai penghubung…. Kalau saja aku bisa tahu itu lebih awal, gak perlu aku susah-susah dan berpusing-pusing ria lihat query jalan tapi data tidak keluar…

But look at good side, emang ada… :D … next time harus lebih teliti kalau mengubah query jangan asal comot, kalau tidak mau berjam-jam melototin query yang “sepertinya” benar.

Have a nice coding!

Aku harus nikah?

Kenyataan yang harus aku hadapi sekarang adalah aku harus menikah secepatnya. Bukan karena alasan atau sebab seperti married by accident or apalah, tapi karena aku sudah cukup lama pacaran dengan pacar aku sekarang. Mungkin sih tidak terlalu lama, cuman 6 tahun, ya 6 tahun.

Kalau ditanya apakah aku siap apa tidak, sudah pasti jawabannya adalah tidak. Wkwkwkww, sungguh aneh memang. Aku belum siap, tapi sebentar lagi akan menikah. Makanya itu ini aku beri judul harus, karena seperti sebuah keharusan. Ingin banget aku lari dari ini, menjauh dan menyendiri menikmati masa lajang. Tapi apa guna seh? klo toh aku besok or lusa juga harus nikah. Dan yang pasti nikahnya juga ama pacar aku sekarang.

Loh kok pasti ama pacar yang sekarang? tidak pingin cari yang lain? Suprise…. itu pertanyaan yang sering banget aku pikirkan. Kenapa aku tidak cari aja pacar yang lain, toh masih banyak cewek yang, mungkin, mau sama aku. Hihihi… tapi semakin aku tanya, jawabannya tetep aja satu. Tidak, tidak ada gunanya aku cari cewek lain. Bukan karena aku ndak payu tapi karena faktor dimana aku sudah bosan dengan PDK, bosan dengan kenyataan bahwa kalau aku pacaran lagi aku harus bisa adaptasi. Juga kenyataan bahwa….. aarrgghhhh gitu deh.

Kembali ke pokok permasalahan, jadi…. siap nggak siap, mau nggak mau aku harus siap and mau. Toh kalau tidak sekarang besok aku juga akan menikah, dan lagi tetep juga ama pacar aku yang sekarang. Jadi kalau akhirnya, at the end, adalah sama, mengapa tidak aku hadapin aja sekarang. Feel better….