תעלול: לייצא נתונים לאקסל ב-PHP

rotemtam ,21/11/2011

 

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

יש שני פתרונות די סטנדרטיים לבעייה:

  • לכווץ את הנתונים לפורמט CSV - Comma Seperated
  • להשתמש בספרייה, צד ג', על מנת לקודד קובץ אקסל מלא

לשתי הפתרונות בעיות מובנות:

  • CSV - לא ניתן לעצב את הפלט, צריך לייצר תהליך נפרד שמעבד את הנתונים הרצויים לנו לפורמט הCSV.  לקוחות לא-טכנולוגיים גם לא תמיד ידעו מה לעשות עם קובץ CSV..
  • להשתמש בספרייה צד ג' - אם אתם עובדים עם טכנולוגיות של מיקרוסופט זה דווקא לא יהווה בעייה גדולה עבורכם, אבל מנסיון הספריות הקיימות בעולם הקוד פתוח בדרך כלל מיושנות או עם API סבוך ותיעוד קלוקל.  כך למשל בפייתון הפתרון היחיד ליצירת קובץ אקסל היא ספריית xlwt, אשר תומכת באקסל עד גרסה 2003 ובעלת API לא נעים במיוחד.

תעלול ה-Mime-type

השיטה המובאת כאן מנצלת תעלול קטן שאפשר לעשות בmime-type שמחזירים מהשרת על מנת להגיש את טבלאות הhtml שכבר יש לכם איך ליצור (בדוגמה שלנו זה המצב, בכל מקרה).  והיא נסמכת על שני דברים: האחד, הדפדפן משתמש בטבלה קטנה שיש אצלו בשביל להחליט איך לפתוח כל קובץ שהוא מקבל, האם לנסות להציג אותו בדפדפן או להשתמש בתוכנה צד ג', או לנסות להריץ אותו כקובץ exectuable.  במקרה שלנו הMime-type של קובץ אקסל הוא:

application/vnd.ms-excel

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

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

  • התוכן נפתח ישירות באקסל
  • שימוש חוזר בקוד שכבר יצרנו (בתאימות עם עקרון DRY) עבור הצגת הנתונים בדפדפן
  • אין צרוך ללמוד API של ספרייה צד ג' כלשהי

דוגמה ב-php:

<?php
 
header('Content-Type: application/vnd.ms-excel; ');
 
?>
 
<table>
    <tr>
        <td></td>
        <td>First Name</td>
        <td>Last Name</td>
    </tr>
    <tr>
        <td>1</td>
        <td>Yosi</td>
        <td>Cohen</td>
    </tr>
    <tr>
        <td>2</td>
        <td>Israel</td>
        <td>Israeli</td>
    </tr>
    <tr>
        <td>3</td>
        <td>Sara</td>
        <td>Levi</td>
    </tr>
</table>

תגובה