از زمانی که ویندوز را رها کردم بعضی مشکلات که روی ویندوز بود داره از ذهنم میره و مبنا را بر روی لینوکس و نرمافزار های لینوکسی گذاشتهام که خوب بعضی جا ها باعث بروز مشکلاتی میشه ، بالاخره بیش از ۹۸ درصد کاربران روی کامپیوتر هاشون ویندوز دارن و از برنامههای ویندوزی استفاده میکنند. این مشکل مربوط به نمایش خروجی های 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 و فایل هاش هم به عنوان نمونه قرار داده شد.
سلام
با این کار اگر فایل csv اول چندین ستون داشته باشد ،کل ستون ها در یک ستون جمع میشود .
خیر دوست عزیز اینطور که شما میگین نیست ،من توی تمام پروژه هام از همین کد استفاده میکنم. Excel هر Encoding ی را برای فایل های CSV قبول نمیکنه. موضوع ستون ها به BOM ربطی نداره و شما باید به درستی از TAB و CRLF برای نمایش صحیح ستون ها و سطر ها استفاده کنید. اگه فکر میکنین هنوز متوجه نمیشین بگین تا نمونه کد بگذارم.
ممنون میشم نمونه کد بذارین
من با pdo خروجی csv میگیرم ولی همش به صورت اینکد شده است!
نتونستم با کد شما مشکلمو رفع کنم
با تشکر
به خاطر تاخیر عذرخواهی میکنم.
نمونه کد را به صورت پی نوشت در انتهای پست قرار دادم.
فقط اینکه اطلاعات شما حتما باید UTF-8 باشه (البته هر چیز دیگه ای میتونه باشه اما نمونه کد من UTF-8 هستش) ، در پایان خطوط حتما r\n\ بگذارین و ستون ها را با TAB یا همون t\ جدا کنید.
یک Screen Shot از Excel هم براتون قرار دادم تا خروجی را روی سیستم من ببینین (البته ویندوز روی ماشین مجازی هست و من ubuntu را به ویندوز و LibreOffice Calc را به Excel ترجیح میدم.).
اگه سوال دیگه ای بود لطفا با ایمیل unique روی geekfarsi.com به صورت خصوصی مطرح کنید.
موفق باشین.
بسیار ممنونم از آموزش بسیار مفیدت
آقا ممنون ! نجات بخش بود این پست!
درود بر شما
کارم راه افتاد
بهترین ها رو واست آرزو میکنم.
موفق باشید
با تشکر فراوان از شما، فقط می تونم بگم فوق العاده بود. هر چند باید اعتراف کنم بعد از تکمیل برنامه، خودم هم متوجه نشدم چه جوری تونستم سورس برنامه اصلی ام رو جوری تغییر بدم که مشکل بخوبی حل بشه! از ابتدا تا آخرش یه جورایی خودجوش بدون اینکه بعد نوشتن برنامه خودم هم متوجه بشم چیکار انجام داده ام!!! چونکه کاری که من داشتم انجام می دادم با مورد معرفی شده توسط شما کاملاً متفاوت بود. موفق باشین
عالی بود
خسته نباشید
به من که زیاد کمک کرد
خدا پدر مادرتو بیامرزه کارم بعد کلی گشتن راه افتاد
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’;
}?>
سلام. مطلبتو خوندم خیلی چیزا یاد گرفتم . مرسی که علم خودت رو به اشتراک میزاری.
سلام و خدا قوت به شما،
آموزش بسیار خوبی بود. منتها من درگیر انجام یک پروژه هستم و دوست داشتم خروجی کار چند ویژگی دیگه هم داشته باشه:
1- برخی از ستون ها را merge کنم.
2- شماره حساب ها را به صورت نماد علمی نشون نده.
3- برگه ها راست به چپ باشه.
ممنون میشم اگه راهنمایی بفرمایید.
این مواردی که میفرمایین در واقع مربوط به تغییر Format و از قابلیت های Excel هست. خروجی CSV یک خروجی کاملا خام هست از اطلاعاتی که هر فیلد با یک جدا کننده مشخص شده و نوع نمایش و مورا دشما مربوط به خود برنامه Excel میشه که من اطلاعات دقیقی از اون ندارم.
سلام و خسته نباشید،
من با این راهنمایی شما مشکلم حل شده، برای خروجی اکسل تا 200 رکورد مشکلی نداره. اما از سطر 200 به بعد تا آخر رو نمیاره. نمی دونین چه جوری این مشکل رو میشه رفعش کرد؟
احتمالا مشکل شما مربوط به کدی میشه که دارین خروجی را میگیرین. اگه روی query دارین limit میگذارین اون را چک کنین. اگه دارین با یک شمارنده میشمارین اون را بررسی کنین. ربطی به راهنمایی که من کردم نداره.
فقط می تونم بگم خدا خیرت بده.بسیار متشکرم