אם חשקה נפשכם במערכת לינקים יפים (פרמלינקס) לאתרכם, כאן תוכלו למצוא מדריך פשוט וקל שיזיז אתכם בכיוון.

אחד הדברים שיותר מעצבנים אותי כמפתח הוא לשמוע על אנשים ששילמו סכומים ניכרים על אתר ולראות איך המפתח זרק דווקא בנקודות החשובות. במקרה הספציפי אני מדבר בעיקר על לינקים יפים (permalinks) כשבמקרים רבים יוצא לי לראות שורות כתובת מחרידות ומפחידות, שלא לדבר על כך שהן לא ידידותיות להקלדה. במיוחד התעצבנתי לראות איך לקוח הוריד אתר קיים (שכבר עבד כשורה והמפתח כבר קיבל עליו תשלום) רק כדי לבנות אותו מחדש פחות טוב.

השימוש במשתני GET הוא אומנם פשוט ונוח בשלב הפיתוח ומאפשר לפעמים למפתח גמישות רבה יותר בזמן העבודה העצמית. אך ברגע שהאתר עולה לשרת החי אין כיום מקום לקישורים מבוססי משתנים – לא מבחינת הקריאות למשתמש ולא מבחינת ה SEO.
המעבר ממערכת מבוססת משתני get למערכת מבוססת פרמלינקים הוא הרבה פחות מסובך ממה שנהוג לחשוב. רוב סביבות הפיתוח (frameworks) הנפוצות (בין אם אתם משתמשים ב CMS כגון וורדפרס או דרופל ובין אם אתם משתמשים ב framework כגון קוד-איגנייטר) מכילות תמיכה מובנית בלינקים יפים שמקילה מאוד על בניית הישום, אך לא תמיד אנחנו באמת זקוקים לפריימוורק מלא. פעמים רבות, עבור אתר קטן יחסית נרצה משהו בסיסי יחסית ובמקרים שכאלה אפשר לממש מערכת פרמלינקים פשוטה בכמה דקות עבודה.

הערה: בטוח שיש עוד עשרות דרכים לממש את מה שכתבתי כאן, אולי חלקן יותר טובות, אולי חלקן פחות ובטוח שאפשר להרחיב כאן עוד רבות. כך או כך, המאמר הזה בא לספק סקירה בסיסית ומהירה שכל מפתח ממוצע יוכל לקחת ולהמשיך אותה הלאה לכיוון שלו.

ישנן (לפחות) שתי שיטות נפוצות כיום כדי לייצר מערכת לינקים נקיים, שתיהן מצריכות עבודה עם קובץ htaccess (ולכן יותר רלוונטיות לשרתי אפאצ'י למרות שגם ל IIS יש מחלקה שאמורה לטפל בנושא) ומצריכות מעורבות שונה ברמות הקוד אך בהתאם ידע רלוונטי ב RegEx.

הפניות על בסיס htaccess
הדרך הראשונה, משתמשת בכתיבה של מערך חוקי הפניות בקובץ ה htaccess. דרך זו לעיתים תהיה פשוטה יותר ונעדיף להשתמש בה על מנת לבצע הסבה לאתר קיים שכן היא לא מצריכה לעשות כל שינוי בקוד המקור של האתר. מצד שני, כאשר האתר גדול ומורכב מערך החוקים יכול להיות ענק וכבר ראיתי קבצי htaccess של כ 100 שורות.
ננתח לרגע את הכתובת הזו :

www.example.com/index.php?dir=site&page=stories&op=allStories

יש לנו פה קובץ index.php שמטפל בתצוגת העמוד ו 3 פרמטרים של GET שאחראים לתצוגת התוכן. אם נרצה להמיר את המערכת לשימוש בלינקים יפים נוכל להשתמש בכלל htaccess כזה כדי לטפל בה:

RewriteRule ^(.*)/(.*)/(.*)/$ index.php?dir=$1&page=$2&op=$3

מעכשיו נוכל להשתמש בכתובת שהיא הרבה יותר ברורה ונקיה:

www.example.com/site/stories/allStories

הבעיה בשימוש בשיטה הזו, היא מה קורה אם יש יותר מקובץ php אחד שאמור לקבל משתנים ברחבי האתר? מה קורה אם יש עמודים שצריכים רק שני פרמטרים ואילו אחרים שצריכים יותר? כאמור, מפתח מנוסה יוכל ליצר סט כללים חכם על בסיס RegEx, מפתח קצת פחות מנוסה יכול להעדיף להעביר הכל אל ה PHP ופשוט לתת לו לטפל בכל.

טיפול ברמת ה PHP
השיטה שבה אני מעדיף להשתמש שאולה מעולם ה mvc למרות שהדרך שאציג פה היא בסיסית מאוד והיא לא באמת מדריך לבניית mvc. זו שיטה לא רעה בכלל כשמתחילים לבנות את האתר מהבסיס למרות שאפשר, במאמץ מסויים, להשתמש בה כדי להסב מערכת קיימת.
השלב הראשון יהיה לבנות את קובץ ה htacess. הקובץ הזה כאמור מטפל בכל ההפניות של האתר, אנחנו פשוט נתעלם מהגדרות מפורכות ונפנה הכל אל עמוד index.php

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

אנחנו מפעילים את מנוע שכתוב הכתובות (שורה 2) ומגדירים את שורש הכתובת כ / (שורה 3). שורות 4 ו 5 מגדירות למערכת שבמקרה וביקשנו קובץ או תיקיה והן אכן קיימות יש להגיש אותן ולא לבצע הפניה. לבסוף, השורה השישית מגדירה שכל התוכן צריך להגיע אל index.php.

השלב הבא יהיה להגדיר את מבנה הכתובת שלנו. למרות שתמיד יש רק קובץ אחד שמבצע את כל הטיפול במערכת, עדיין שימוש במערכת כתובות מוגדרת יקל על העבודה. עבור אתרים לא מסובכים מדי אני מעדיף להשתמש במערכת של שני פרמטרים בצורה הבאה:

/page/item

כאשר האתר מצריך קצת יותר מרק הצגה של תוכן, אני מוסיף פרמטר נוסף שמגדיר את הפונקציונאליות הרלוונטית לעמוד.

/page/item/function
/page/function/item

אישית, אני מעדיף את האופציה הראשונה, כך אני יכול להגדיר את הפונקציה הדיפולטית ולהשמיט את הפרמטר. נניח, עמוד של פוסט שהמזהה שלו ב DB הוא 42 יקבל את הלינק הבא:

example.com/post/42

אם אני רוצה לערוך את האיטם, הלינק שלו יהיה

example.com/post/42/edit

כמובן שאת 42 (ה id של הפוסט) אפשר להחליף בטייטל רלוונטי עם טיפול מתאים ולקבל משהו כזה:

example.com/post/the-answer-to-life-universe-and-everyting

היות והכל מגיע אל קובץ index.php אני מעדיף להשתמש בפרמטר REQUEST_URI של השרת כדי לקבל את הנתיב.
כך, במקרה שלי הפרמטר יחזיר את המחרוזת post/42/edit שמכילה את המידע שאני זקוק לו. לחילופין, אפשר לעשות את זה על בסיס הפניה מה htacess על מנת לקבל את המידע הזה כפרמטר מסוג GET.

$url = trim($_SERVER['REQUEST_URI'] , '/');
$parms = explode(, '/');
$list($handler, $item, $action) = $parms;

השלב הראשון יהיה הסרה של סלאשים עודפים בעזרת פונקציית הקיצוץ (trim) – הפונקציה תסיר את הסלאשים מתחילת ומסוף המחרוזת וכך תקטין את הסיכוי לתקלה בגלל סלאשים עודפים.
השימוש בפונקציה explode על בסיס הסלאש (/) מייצר מערך שכל איבר שלו מכיל אובייקט אחד מתוך הכתובת.
לבסוף, שימוש ב list מאפשר לי למפות את איברי המערך אל המשתנים היעודיים שלי. במקרה הזה השתמשתי במשתנים פשוטים, אך ככל שהסיבוכיות של המערכת גדלה, רוב הסיכוי שנרצה לעבוד עם מערך אחד גלובאלי שמחזיק את כל הפרמטרים הרלוונטים.

ראשית, יש לקרוא לעמוד המטפל, אם בעבר היינו קוראים לו בצורה:

example.com/post.php?

הרי שעכשיו אנחנו צריכים לקרוא לעמוד הזה מתוך index.php, זאת נעשה בעזרת include

include ('theme/'.$handler.".php");

מסיבות של סדר וניקיון בסביבת העבודה, אני מעדיף לייצר תיקיה בשם theme ושם לשים את קבצי ה PHP שמטפלים בתצוגה, עבור מפתחי mvc זה בטח נראה כמו חילול הקודש כי זה למעשה קובץ שהוא גם controller וגם view, אך כאמור, אני לא בונה פה mvc, אלא מערכת בסיסית ופשוטה.

עבור כל אחד מסוגי העמודים אני מחזיק קובץ php תואם ( post.php, page.php, search.php וכ') כאשר אותו קובץ מחזיק את הפונקציונאליות הרלוונטית לקובץ וקורא לתוכן הנדרש על בסיס המאפיינים המוגדרים במשתנים item ו action.

סיכום
לא פעם ולא פעמיים כששאלתי מפתח מדוע הוא לא משתמש בלינקים יפים קיבלתי הסבר על למה השימוש בפרמלינקס הוא מסובך יחסית. כפי שאפשר לראות במאמר זה, המימוש הוא לחלוטין לא מסובך אם בונים את המערכת נכון מההתחלה. הרווח פה הוא עצום – הן מבחינת הקריאות של הלינק שתעזור למשתמש להבין איפה הוא נמצא, הן מבחינת ה SEO שמספק למנוע החיפוש מידע לגבי התוכן בעמוד והן מצד המפתח שמקבל קוד קצת יותר גדול מבחינת תיקיות וקבצים, אבל הרבה יותר ברור, מסודר ונוח לתחזוקה.

לדעתי, שיטת העבודה הזו מהווה באופן די טבעי מקפצה אל תחום ה mvc ותאפשר למפתח המתחיל לעבור במהירות אל סביבות mvc קימות ולהאיץ את קצב הפיתוח.