گیک فارسی

نوشته های یک گیک فارسی از فعالیت ها ،‌ علاقه مندی ها و نقد هایش

خروجی CSV فارسی برای Excel در PHP

۱۶ دیدگاه‌ها

از زمانی که ویندوز را رها کردم بعضی مشکلات که روی ویندوز بود داره از ذهنم میره و مبنا را بر روی لینوکس و نرم‌افزار های لینوکسی گذاشته‌ام که خوب بعضی جا ها باعث بروز مشکلاتی میشه ، بالاخره بیش از ۹۸ درصد کاربران روی کامپیوتر هاشون ویندوز دارن و از برنامه‌های ویندوزی استفاده میکنند. این مشکل مربوط به نمایش خروجی های CSV توی Excel هست که بسیار توی برنامه نویسی وب پر استفاده هستش و معمولاً خیلی از گزارش ها را به فرمت CSV و Xls میدیم.

من زیاد از فرمت های انحصاری خوشم نمیاد مخصوصاً Xls و ترجیح میدم وقتی CSV به این راحتی هست از Xls استفاده نکنم مگر اینکه واقعاً مجبور بشم.

اما مشکلی که تقریباً همه دارند اینه که وقتی خروجی utf-8 بگیری توسط php و حتی BOM مربوطه را هم بگذاری باز هم Excel نمیفهمه فایل را باید با Encoding درست یعنی utf-8 نمایش بده. خوب با کمی جستجو و استفاده از تجربه دیگران متوجه شدم که Excel تنها وقتی Encoding را روی UTF-16LE میگذاریم و BOM را هم اول فایل قرار میدیم به راحتی فارسی (کلاً یونیکد) را تشخیص و درست نمایش میده.

خوب با این فرض دیگه کد نویسیش سخت نیست و چون نمیخوام این تغییر را دونه به دونه روی هر فیلدی اعمال کنم همون فایل utf-8 را ایجاد میکنم و از روش یک فایل با utf-16le میسازم:

$fh = fopen($utf16le_file,"w");
fwrite($fh, chr(255).chr(254)); //BOM For UTF-16LE
fwrite($fh, mb_convert_encoding(file_get_contents($utf8_file) , 'UTF-16LE', 'UTF-8'));
fclose($fh);

به همین راحتی انجام شد و نیازی به سر و کله زدن با کامپوننت های Excel برای PHP نیست.

پی نوشت ۱: یک نمونه کد برای راهنمایی بیشتر دوستان برای دانلود قرار دادم.

پی نوشت ۲: دو تا نکته هست که اگه دوستان دقت نداشته باشند با مشکل روبرو میشوند. یکی اینکه برای Delimiter باید حتما از TAB یا همون t\ استفاده کنند و نکته دیگه اینکه اگه از تابع fputcsv استفاده میکنید. توجه داشته باشین که مقادیر را داخل تابع به utf16le تبدیل نکنید. کل فایل csv را روی دیسک ذخیره کنید و یکجا همه را به utf16le تبدیل کنید. علتش اینه که fputcsv مقادیر Delimiter و n\ را utf-8 ذخیره میکنه و به مشکل میخورید.

پی نوشت ۳: یکسری دوستان گلایه داشتند که چرا من از فایل متنی به عنوان Data ورودی استفاده کردم که نسخه MySQL به همراه Database و فایل هاش هم به عنوان نمونه قرار داده شد.



برچسب‌ها:

  1. دوست گفت:

    سلام

    با این کار اگر فایل csv اول چندین ستون داشته باشد ،کل ستون ها در یک ستون جمع میشود .

    1. یونیک مدیر گفت:

      خیر دوست عزیز اینطور که شما میگین نیست ،‌من توی تمام پروژه هام از همین کد استفاده میکنم. Excel هر Encoding ی را برای فایل های CSV قبول نمیکنه. موضوع ستون ها به BOM ربطی نداره و شما باید به درستی از TAB و CRLF برای نمایش صحیح ستون ها و سطر ها استفاده کنید. اگه فکر میکنین هنوز متوجه نمیشین بگین تا نمونه کد بگذارم.

  2. ناشناس گفت:

    ممنون میشم نمونه کد بذارین
    من با pdo خروجی csv میگیرم ولی همش به صورت اینکد شده است!
    نتونستم با کد شما مشکلمو رفع کنم
    با تشکر

    1. یونیک مدیر گفت:

      به خاطر تاخیر عذرخواهی میکنم.
      نمونه کد را به صورت پی نوشت در انتهای پست قرار دادم.
      فقط اینکه اطلاعات شما حتما باید UTF-8 باشه (البته هر چیز دیگه ای میتونه باشه اما نمونه کد من UTF-8 هستش) ، در پایان خطوط حتما r\n\ بگذارین و ستون ها را با TAB یا همون t\ جدا کنید.
      یک Screen Shot از Excel هم براتون قرار دادم تا خروجی را روی سیستم من ببینین (البته ویندوز روی ماشین مجازی هست و من ubuntu را به ویندوز و LibreOffice Calc را به Excel ترجیح میدم.).
      اگه سوال دیگه ای بود لطفا با ایمیل unique روی geekfarsi.com به صورت خصوصی مطرح کنید.
      موفق باشین.

  3. وبینه گفت:

    بسیار ممنونم از آموزش بسیار مفیدت

  4. ناشناس گفت:

    آقا ممنون ! نجات بخش بود این پست!

  5. داود گفت:

    درود بر شما
    کارم راه افتاد
    بهترین ها رو واست آرزو میکنم.
    موفق باشید

  6. رامین گفت:

    با تشکر فراوان از شما، فقط می تونم بگم فوق العاده بود. هر چند باید اعتراف کنم بعد از تکمیل برنامه، خودم هم متوجه نشدم چه جوری تونستم سورس برنامه اصلی ام رو جوری تغییر بدم که مشکل بخوبی حل بشه! از ابتدا تا آخرش یه جورایی خودجوش بدون اینکه بعد نوشتن برنامه خودم هم متوجه بشم چیکار انجام داده ام!!! چونکه کاری که من داشتم انجام می دادم با مورد معرفی شده توسط شما کاملاً متفاوت بود. موفق باشین

  7. رسول گفت:

    عالی بود
    خسته نباشید
    به من که زیاد کمک کرد

  8. محسن گفت:

    خدا پدر مادرتو بیامرزه کارم بعد کلی گشتن راه افتاد

    get_results(“SELECT * FROM {$table_prefix}productcares”);
    $fh = fopen(“output.csv”,”w”);
    fwrite($fh, chr(255).chr(254)); fwrite($fh, make_utf16le(“نام محصول\tسریال\tتاریخ فروش\tخریدار\tنماینده-فروشنده\tوضعیت\tشماره پیگیری\tنصاب\r\n”));
    foreach ($product as $list):
    fwrite($fh, make_utf16le($list->name.”\t”.$list->serial.”\t”.$list->sell_date.”\t”.getuserinfo($list->customerid).”\t”.getsellerinfo($list->seller_id).”\t”.$list->status.”\t”.$list->randcode.”\t”.$list->sellern.”\r\n”));

    endforeach;
    fclose($fh);
    echo ‘listget’;
    }?>

  9. قاسم گفت:

    سلام. مطلبتو خوندم خیلی چیزا یاد گرفتم . مرسی که علم خودت رو به اشتراک میزاری.

  10. هدایت الله دلاکی گفت:

    سلام و خدا قوت به شما،

    آموزش بسیار خوبی بود. منتها من درگیر انجام یک پروژه هستم و دوست داشتم خروجی کار چند ویژگی دیگه هم داشته باشه:
    ۱- برخی از ستون ها را merge کنم.
    ۲- شماره حساب ها را به صورت نماد علمی نشون نده.
    ۳- برگه ها راست به چپ باشه.

    ممنون میشم اگه راهنمایی بفرمایید.

    1. یونیک مدیر گفت:

      این مواردی که میفرمایین در واقع مربوط به تغییر Format و از قابلیت های Excel هست. خروجی CSV یک خروجی کاملا خام هست از اطلاعاتی که هر فیلد با یک جدا کننده مشخص شده و نوع نمایش و مورا دشما مربوط به خود برنامه Excel میشه که من اطلاعات دقیقی از اون ندارم.

  11. حسن گفت:

    سلام و خسته نباشید،

    من با این راهنمایی شما مشکلم حل شده، برای خروجی اکسل تا ۲۰۰ رکورد مشکلی نداره. اما از سطر ۲۰۰ به بعد تا آخر رو نمیاره. نمی دونین چه جوری این مشکل رو میشه رفعش کرد؟

    1. یونیک مدیر گفت:

      احتمالا مشکل شما مربوط به کدی میشه که دارین خروجی را میگیرین. اگه روی query دارین limit میگذارین اون را چک کنین. اگه دارین با یک شمارنده میشمارین اون را بررسی کنین. ربطی به راهنمایی که من کردم نداره.

  12. عمادالدین پورسینا گفت:

    فقط می تونم بگم خدا خیرت بده.بسیار متشکرم

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *