Stream_get_contents thành mảng php

Nếu ai đã từng tham gia các dự án outsource cho khách hàng Nhật Bản thì đều gặp bài toán thông tin phổ biến lấy dữ liệu từ cơ sở dữ liệu và xuất ra báo cáo

ID,従業員コード,氏名※,フリガナ
1,A01.,山,カミソヤマ ユニ
2,A02,上曽山 ゆに,ソ ユニ
3,A03,"上曽山\" 上曽山",ゆに
6 cho người dùng. Nghe rất đơn giản, ta chỉ cần sử dụng hàm có sẵn của
ID,従業員コード,氏名※,フリガナ
1,A01.,山,カミソヤマ ユニ
2,A02,上曽山 ゆに,ソ ユニ
3,A03,"上曽山\" 上曽山",ゆに
7

fputcsv ( resource $handle , array $fields [, string $delimiter = "," [, string $enclosure = '"' [, string $escape_char = "\\" ]]] ) : int

  • xử lý. Con trỏ tệp
  • lĩnh vực. Data array (dữ liệu hàng)
  • dấu phân cách. Ký tự ngăn cách các trường (Thường là dấu
    ID,従業員コード,氏名※,フリガナ
    1,A01.,山,カミソヤマ ユニ
    2,A02,上曽山 ゆに,ソ ユニ
    3,A03,"上曽山\" 上曽山",ゆに
    
    8 hoặc
    ID,従業員コード,氏名※,フリガナ
    1,A01.,山,カミソヤマ ユニ
    2,A02,上曽山 ゆに,ソ ユニ
    3,A03,"上曽山\" 上曽山",ゆに
    
    9)
  • bao vây. Ký tự sử dụng để kiểm tra xem một trường được bắt đầu và kết thúc
  • thoát_char. Escape ký tự (ko biết cách dịch nào cho hợp lý) để tắt cơ chế này, hãy đặt giá trị trống (“”)

    Ví dụ.

    ID,従業員コード,氏名※,フリガナ
    1,A01,山,"カミソヤマ ユニ"
    2,A02,上曽山 ゆに,"ソ ユニ"
    3,A03,"上曽山\" 上曽山",ゆに
    
    0
    Stream_get_contents thành mảng php

Mã hóa, bài toán muôn thuở

Đi tới các vấn đề phức tạp hơn

Chúng ta có nhận thêm yêu cầu là muốn chuyển đổi dữ liệu trong csv này từ bản gốc

ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
1 sang
ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
2 ~ WTF. 🎱

Lý do người Nhật vẫn sử dụng

ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
2 chỉ gói đơn giản gọn trong 1 từ khóa Legacy.
ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
2,
ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
5 đều là những mã hóa tiêu chuẩn được sử dụng trước khi mà
ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
1 trở nên phổ biến như ngày hôm nay. Ngoài ra còn một lý do nữa mình nghĩ cũng quan trọng khi mà
ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
2 chỉ cần sử dụng mã hóa
ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
8 trong khi
ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
1 cần tới
$stdout = fopen('php://stdout', 'w');
fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
0 để mã hóa tiếng Nhật nói chung và
$stdout = fopen('php://stdout', 'w');
fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
1 nói riêng 🎃

Ở đây mình có mã cơ sở như sau. Thay vì đọc dữ liệu từ cơ sở dữ liệu, chúng được hard code trong 1 mảng

function convert($fields) {
    $result = [];
    foreach ($fields as $field) {
        $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
    }
    return $result;
}

function arr2csv($rows) {
    $fp = fopen('php://temp', 'r+b');
    foreach($rows as $fields) {
        // Convert row data from UTF-8 to Shift-JS
        $fields = convert($fields);
        fputcsv($fp, $fields);
    }
    rewind($fp);
    // Convert CRLF
    $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
    fclose($fp);
    return $tmp;
}

function writecsv($filename) {
    // Header of csv
    $header = [
        'ID',
        '従業員コード', // Employee code
        '氏名※',       // Name
        'フリガナ',     // Furigana
    ];
    // Sample data from database
    $data = [
        [
            "id" => 1,
            "code" => "A01",
            "name" => "山",
            "furigana" => "カミソヤマ ユニ"
        ],
        [
            "id" => 2,
            "code" => "A02",
            "name" => "上曽山 ゆに",
            "furigana" => "ソ ユニ",
        ],
        [
            "id" => 3,
            "code" => "A03",
            "name" => '上曽山\\" 上曽山',
            "furigana" => "ゆに",
        ],
    ];
    // Prepend header
    array_unshift($data, $header);
    // Open file to write stream data
    $f = fopen($filename, 'w+');
    fwrite($f, arr2csv($data));
    fclose($f);
}

writecsv("output.csv");

  • Kỳ vọng

    ID,従業員コード,氏名※,フリガナ
    1,A01.,山,カミソヤマ ユニ
    2,A02,上曽山 ゆに,ソ ユニ
    3,A03,"上曽山\" 上曽山",ゆに
    

  • đầu ra

    ID,従業員コード,氏名※,フリガナ
    1,A01,山,"カミソヤマ ユニ"
    2,A02,上曽山 ゆに,"ソ ユニ"
    3,A03,"上曽山\" 上曽山",ゆに
    

    To idea will see the row number 1, column Furigana. Giá trị

    $stdout = fopen('php://stdout', 'w');
    fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
    fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
    fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
    fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
    
    2 được đặt trong dấu ấn
    $stdout = fopen('php://stdout', 'w');
    fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
    fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
    fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
    fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
    
    3, trở thành
    $stdout = fopen('php://stdout', 'w');
    fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
    fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
    fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
    fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
    
    4. Nếu chỉ xem trên các chương trình như Open Office, MS Excel sẽ rất khó phát hiện. Ở đây mình có 2 ảnh mở trên
    $stdout = fopen('php://stdout', 'w');
    fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
    fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
    fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
    fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
    
    5 và
    $stdout = fopen('php://stdout', 'w');
    fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
    fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
    fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
    fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
    
    6 sẽ biết điều đó.
    Stream_get_contents thành mảng php
    Stream_get_contents thành mảng php

Trong dữ liệu bên ngoài hàng cuối cùng chứa ký tự kép trích dẫn

$stdout = fopen('php://stdout', 'w');
fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
3 ra thì các hàng ở trên nó hoàn toàn không chứa ký tự đó. Cần phải có lý do gì để quấn lại thế mà 😢

Sau khi thử loại trừ bằng cách xóa dần các ký tự bên trong giá trị của các trường, mình phát hiện thêm 1 điều

Giá trị trên mỗi hàng của csv chỉ bị xóa dấu ngoặc kép bổ sung thêm trong trường hợp có chứa ký tự 「ソ」、「十」 hoặc ký tự nào nữa không rõ ???

$stdout = fopen('php://stdout', 'w');
fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));

UTF-8 ソ: 0xe382bd
UTF-8 十: 0xe58d81
Shift-JIS ソ: 0x835c
Shift-JIS 十: 0x8f5c

Nhìn vào mã trên ta có thể thấy UTF-8 cần 3 byte trong khi Shift-JIS chỉ cần 2 byte cho các ký tự tiếng nhật. Tools

「ソ」=「0x8F5C」=「0x8F」+「0x5C」

「十」=「0x8f5c」=「0x8f」+「0x5c」

Sau khi đã cố gắng tìm kiếm nguyên nhân trên Google mà vẫn không cho kết quả tốt, thì quyết định cuối cùng là thử nghiệm hướng tới phương pháp

$stdout = fopen('php://stdout', 'w');
fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
8 bên trong
$stdout = fopen('php://stdout', 'w');
fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
9

  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }

Người giới thiệu

Để đoạn ý

UTF-8 ソ: 0xe382bd
UTF-8 十: 0xe58d81
Shift-JIS ソ: 0x835c
Shift-JIS 十: 0x8f5c
4 xử lý ký tự bổ sung
UTF-8 ソ: 0xe382bd
UTF-8 十: 0xe58d81
Shift-JIS ソ: 0x835c
Shift-JIS 十: 0x8f5c
5 vào từng trường giá trị trên mỗi hàng-csv có điều kiện sau

/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (...
  (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
  ...
) {

Rõ ràng khi

UTF-8 ソ: 0xe382bd
UTF-8 十: 0xe58d81
Shift-JIS ソ: 0x835c
Shift-JIS 十: 0x8f5c
6 được đặt giá trị mặc định
UTF-8 ソ: 0xe382bd
UTF-8 十: 0xe58d81
Shift-JIS ソ: 0x835c
Shift-JIS 十: 0x8f5c
7 nó chịu điều kiện
UTF-8 ソ: 0xe382bd
UTF-8 十: 0xe58d81
Shift-JIS ソ: 0x835c
Shift-JIS 十: 0x8f5c
8 vậy còn điều kiện
UTF-8 ソ: 0xe382bd
UTF-8 十: 0xe58d81
Shift-JIS ソ: 0x835c
Shift-JIS 十: 0x8f5c
9 tức là sao ?

#define FPUTCSV_FLD_CHK(c) memchr(ZSTR_VAL(field_str), c, ZSTR_LEN(field_str))
// ---> Return:
// A pointer to the first occurrence of value(c) in the block of memory pointed by ptr(field_str).
// If the value is not found, the function returns a null pointer.

Bằng chứng để có kết quả đầu ra khác chắc chắn bên trong giá trị các trường có chứ không phải ký tự dấu gạch chéo ngược

  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
0

Test try with sample after.

  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
1

#include 
#include 

#define FPUTCSV_FLD_CHK(c) memchr(str, c, strlen(str))

int main()
{
    const char str[] = "We Make It Awesome";
    const char ch = 'e';
    char *ret;

    ret = FPUTCSV_FLD_CHK(ch);

    if (ret != NULL) {
        printf ("'%c' found at position %d.\n", ch, ret-str+1);
        printf("String after |%c| is - |%s|\n", ch, ret);
    } else {
        printf ("'%c' not found.\n", ch);
    }

    return 0;
}

  • đầu ra

    function convert($fields) {
        $result = [];
        foreach ($fields as $field) {
            $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
        }
        return $result;
    }
    
    function arr2csv($rows) {
        $fp = fopen('php://temp', 'r+b');
        foreach($rows as $fields) {
            // Convert row data from UTF-8 to Shift-JS
            $fields = convert($fields);
            fputcsv($fp, $fields);
        }
        rewind($fp);
        // Convert CRLF
        $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
        fclose($fp);
        return $tmp;
    }
    
    function writecsv($filename) {
        // Header of csv
        $header = [
            'ID',
            '従業員コード', // Employee code
            '氏名※',       // Name
            'フリガナ',     // Furigana
        ];
        // Sample data from database
        $data = [
            [
                "id" => 1,
                "code" => "A01",
                "name" => "山",
                "furigana" => "カミソヤマ ユニ"
            ],
            [
                "id" => 2,
                "code" => "A02",
                "name" => "上曽山 ゆに",
                "furigana" => "ソ ユニ",
            ],
            [
                "id" => 3,
                "code" => "A03",
                "name" => '上曽山\\" 上曽山',
                "furigana" => "ゆに",
            ],
        ];
        // Prepend header
        array_unshift($data, $header);
        // Open file to write stream data
        $f = fopen($filename, 'w+');
        fwrite($f, arr2csv($data));
        fclose($f);
    }
    
    writecsv("output.csv");
    
    0

Được rồi, đọc tới đây chắc chắn bạn đã hiểu nguyên lý hoạt động của phương thức

  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
2 trong
  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
3. Các cụ thể trong trường hợp này được sử dụng để kiểm tra sự có mặt của ký tự
  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
4 trong giá trị của
  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
5 hay không, nếu có bọc lại giá trị đó bằng dấu ngoặc kép
  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
6

Thử apply trong trường hợp ký tự

  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
7 xem sao nhỉ
Stream_get_contents thành mảng php

function convert($fields) {
    $result = [];
    foreach ($fields as $field) {
        $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
    }
    return $result;
}

function arr2csv($rows) {
    $fp = fopen('php://temp', 'r+b');
    foreach($rows as $fields) {
        // Convert row data from UTF-8 to Shift-JS
        $fields = convert($fields);
        fputcsv($fp, $fields);
    }
    rewind($fp);
    // Convert CRLF
    $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
    fclose($fp);
    return $tmp;
}

function writecsv($filename) {
    // Header of csv
    $header = [
        'ID',
        '従業員コード', // Employee code
        '氏名※',       // Name
        'フリガナ',     // Furigana
    ];
    // Sample data from database
    $data = [
        [
            "id" => 1,
            "code" => "A01",
            "name" => "山",
            "furigana" => "カミソヤマ ユニ"
        ],
        [
            "id" => 2,
            "code" => "A02",
            "name" => "上曽山 ゆに",
            "furigana" => "ソ ユニ",
        ],
        [
            "id" => 3,
            "code" => "A03",
            "name" => '上曽山\\" 上曽山',
            "furigana" => "ゆに",
        ],
    ];
    // Prepend header
    array_unshift($data, $header);
    // Open file to write stream data
    $f = fopen($filename, 'w+');
    fwrite($f, arr2csv($data));
    fclose($f);
}

writecsv("output.csv");
1

  • đầu ra

    function convert($fields) {
        $result = [];
        foreach ($fields as $field) {
            $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
        }
        return $result;
    }
    
    function arr2csv($rows) {
        $fp = fopen('php://temp', 'r+b');
        foreach($rows as $fields) {
            // Convert row data from UTF-8 to Shift-JS
            $fields = convert($fields);
            fputcsv($fp, $fields);
        }
        rewind($fp);
        // Convert CRLF
        $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
        fclose($fp);
        return $tmp;
    }
    
    function writecsv($filename) {
        // Header of csv
        $header = [
            'ID',
            '従業員コード', // Employee code
            '氏名※',       // Name
            'フリガナ',     // Furigana
        ];
        // Sample data from database
        $data = [
            [
                "id" => 1,
                "code" => "A01",
                "name" => "山",
                "furigana" => "カミソヤマ ユニ"
            ],
            [
                "id" => 2,
                "code" => "A02",
                "name" => "上曽山 ゆに",
                "furigana" => "ソ ユニ",
            ],
            [
                "id" => 3,
                "code" => "A03",
                "name" => '上曽山\\" 上曽山',
                "furigana" => "ゆに",
            ],
        ];
        // Prepend header
        array_unshift($data, $header);
        // Open file to write stream data
        $f = fopen($filename, 'w+');
        fwrite($f, arr2csv($data));
        fclose($f);
    }
    
    writecsv("output.csv");
    
    2

Dấu gạch chéo ngược ký tự

  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
8 trong
ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
1 xuất hiện lại trong chuỗi
  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
7 -
ID,従業員コード,氏名※,フリガナ
1,A01,山,"カミソヤマ ユニ"
2,A02,上曽山 ゆに,"ソ ユニ"
3,A03,"上曽山\" 上曽山",ゆに
2. Hóa ra
/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (...
  (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
  ...
) {
2 trong bảng ASCII lại chính là ký tự
  PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char)
  {
    ...
    smart_str csvline = {0};

    ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
    count = zend_hash_num_elements(Z_ARRVAL_P(fields));
    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
      ...
      /* enclose a field that contains a delimiter, an enclosure character, or a newline */
      if (FPUTCSV_FLD_CHK(delimiter) ||
        FPUTCSV_FLD_CHK(enclosure) ||
        (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
        FPUTCSV_FLD_CHK('\n') ||
        FPUTCSV_FLD_CHK('\r') ||
        FPUTCSV_FLD_CHK('\t') ||
        FPUTCSV_FLD_CHK(' ')
      ) {
        char *ch = ZSTR_VAL(field_str);
        char *end = ch + ZSTR_LEN(field_str);
        int escaped = 0;

        smart_str_appendc(&csvline, enclosure);
        while (ch < end) {
          if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
            escaped = 1;
          } else if (!escaped && *ch == enclosure) {
            smart_str_appendc(&csvline, enclosure);
          } else {
            escaped = 0;
          }
          smart_str_appendc(&csvline, *ch);
          ch++;
        }
        smart_str_appendc(&csvline, enclosure);
      } else {
        smart_str_append(&csvline, field_str);
      }
      ...
    } ZEND_HASH_FOREACH_END();
    ...
  }
0

Stream_get_contents thành mảng php

👉 Bảng ASCII

Stream_get_contents thành mảng php

Và có lẽ đó chính là lý do mà giá trị của các trường trong tệp

/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (...
  (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
  ...
) {
4 được bọc bởi dấu
$stdout = fopen('php://stdout', 'w');
fprintf($stdout, "UTF-8 ソ: 0x%s\n", bin2hex('ソ'));
fprintf($stdout, "UTF-8 十: 0x%s\n", bin2hex('十'));
fprintf($stdout, "Shift-JIS ソ: 0x%s\n", bin2hex(mb_convert_encoding('ソ', 'SJIS', 'UTF-8')));
fprintf($stdout, "Shift-JIS 十: 0x%s\n", bin2hex(mb_convert_encoding('十', 'SJIS', 'UTF-8')));
3 một cách bất thường

Stream_get_contents thành mảng php

Và cuối cùng đây là công việc cần ghi nhớ khi chuyển đến csv 📖

Việc cần làm rất đơn giản, chỉ cần đổi lại thứ tự thực hiện chuyển đổi mã hóa sau khi xuất định dạng CSV là được. Và việc đổi thứ tự này cũng giúp chi phí tính toán giảm đi khá nhiều vì chỉ phải thực hiện câu lệnh encode một lần duy nhất, thay vì

/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (...
  (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
  ...
) {
6 lần như phiên bản đầu tiên

function convert($fields) {
    $result = [];
    foreach ($fields as $field) {
        $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
    }
    return $result;
}

function arr2csv($rows) {
    $fp = fopen('php://temp', 'r+b');
    foreach($rows as $fields) {
        // Convert row data from UTF-8 to Shift-JS
        $fields = convert($fields);
        fputcsv($fp, $fields);
    }
    rewind($fp);
    // Convert CRLF
    $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
    fclose($fp);
    return $tmp;
}

function writecsv($filename) {
    // Header of csv
    $header = [
        'ID',
        '従業員コード', // Employee code
        '氏名※',       // Name
        'フリガナ',     // Furigana
    ];
    // Sample data from database
    $data = [
        [
            "id" => 1,
            "code" => "A01",
            "name" => "山",
            "furigana" => "カミソヤマ ユニ"
        ],
        [
            "id" => 2,
            "code" => "A02",
            "name" => "上曽山 ゆに",
            "furigana" => "ソ ユニ",
        ],
        [
            "id" => 3,
            "code" => "A03",
            "name" => '上曽山\\" 上曽山',
            "furigana" => "ゆに",
        ],
    ];
    // Prepend header
    array_unshift($data, $header);
    // Open file to write stream data
    $f = fopen($filename, 'w+');
    fwrite($f, arr2csv($data));
    fclose($f);
}

writecsv("output.csv");
3

  • Kỳ vọng

    ID,従業員コード,氏名※,フリガナ
    1,A01.,山,カミソヤマ ユニ
    2,A02,上曽山 ゆに,ソ ユニ
    3,A03,"上曽山\" 上曽山",ゆに
    

  • đầu ra

    ID,従業員コード,氏名※,フリガナ
    1,A01.,山,カミソヤマ ユニ
    2,A02,上曽山 ゆに,ソ ユニ
    3,A03,"上曽山\" 上曽山",ゆに
    

Xuất file đúng như mong đợi 👍 💯

Chuẩn RFC 4180 & Lỗi chưa được sửa

RFC 4180 một định dạng định dạng chuẩn cho tệp CSV được sử dụng để đọc CSV xuất trong rất nhiều ứng dụng, đơn cử như Bảng tính Google

If ta has 1 sheet with the content after

function convert($fields) {
    $result = [];
    foreach ($fields as $field) {
        $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
    }
    return $result;
}

function arr2csv($rows) {
    $fp = fopen('php://temp', 'r+b');
    foreach($rows as $fields) {
        // Convert row data from UTF-8 to Shift-JS
        $fields = convert($fields);
        fputcsv($fp, $fields);
    }
    rewind($fp);
    // Convert CRLF
    $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
    fclose($fp);
    return $tmp;
}

function writecsv($filename) {
    // Header of csv
    $header = [
        'ID',
        '従業員コード', // Employee code
        '氏名※',       // Name
        'フリガナ',     // Furigana
    ];
    // Sample data from database
    $data = [
        [
            "id" => 1,
            "code" => "A01",
            "name" => "山",
            "furigana" => "カミソヤマ ユニ"
        ],
        [
            "id" => 2,
            "code" => "A02",
            "name" => "上曽山 ゆに",
            "furigana" => "ソ ユニ",
        ],
        [
            "id" => 3,
            "code" => "A03",
            "name" => '上曽山\\" 上曽山',
            "furigana" => "ゆに",
        ],
    ];
    // Prepend header
    array_unshift($data, $header);
    // Open file to write stream data
    $f = fopen($filename, 'w+');
    fwrite($f, arr2csv($data));
    fclose($f);
}

writecsv("output.csv");
6

Stream_get_contents thành mảng php

Thì khi chọn

/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (...
  (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
  ...
) {
7 ta sẽ lấy được nội dung file như sau

function convert($fields) {
    $result = [];
    foreach ($fields as $field) {
        $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
    }
    return $result;
}

function arr2csv($rows) {
    $fp = fopen('php://temp', 'r+b');
    foreach($rows as $fields) {
        // Convert row data from UTF-8 to Shift-JS
        $fields = convert($fields);
        fputcsv($fp, $fields);
    }
    rewind($fp);
    // Convert CRLF
    $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
    fclose($fp);
    return $tmp;
}

function writecsv($filename) {
    // Header of csv
    $header = [
        'ID',
        '従業員コード', // Employee code
        '氏名※',       // Name
        'フリガナ',     // Furigana
    ];
    // Sample data from database
    $data = [
        [
            "id" => 1,
            "code" => "A01",
            "name" => "山",
            "furigana" => "カミソヤマ ユニ"
        ],
        [
            "id" => 2,
            "code" => "A02",
            "name" => "上曽山 ゆに",
            "furigana" => "ソ ユニ",
        ],
        [
            "id" => 3,
            "code" => "A03",
            "name" => '上曽山\\" 上曽山',
            "furigana" => "ゆに",
        ],
    ];
    // Prepend header
    array_unshift($data, $header);
    // Open file to write stream data
    $f = fopen($filename, 'w+');
    fwrite($f, arr2csv($data));
    fclose($f);
}

writecsv("output.csv");
7

Stream_get_contents thành mảng php

Try to use

ID,従業員コード,氏名※,フリガナ
1,A01.,山,カミソヤマ ユニ
2,A02,上曽山 ゆに,ソ ユニ
3,A03,"上曽山\" 上曽山",ゆに
7 read this file coi sao 😃

function convert($fields) {
    $result = [];
    foreach ($fields as $field) {
        $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
    }
    return $result;
}

function arr2csv($rows) {
    $fp = fopen('php://temp', 'r+b');
    foreach($rows as $fields) {
        // Convert row data from UTF-8 to Shift-JS
        $fields = convert($fields);
        fputcsv($fp, $fields);
    }
    rewind($fp);
    // Convert CRLF
    $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
    fclose($fp);
    return $tmp;
}

function writecsv($filename) {
    // Header of csv
    $header = [
        'ID',
        '従業員コード', // Employee code
        '氏名※',       // Name
        'フリガナ',     // Furigana
    ];
    // Sample data from database
    $data = [
        [
            "id" => 1,
            "code" => "A01",
            "name" => "山",
            "furigana" => "カミソヤマ ユニ"
        ],
        [
            "id" => 2,
            "code" => "A02",
            "name" => "上曽山 ゆに",
            "furigana" => "ソ ユニ",
        ],
        [
            "id" => 3,
            "code" => "A03",
            "name" => '上曽山\\" 上曽山',
            "furigana" => "ゆに",
        ],
    ];
    // Prepend header
    array_unshift($data, $header);
    // Open file to write stream data
    $f = fopen($filename, 'w+');
    fwrite($f, arr2csv($data));
    fclose($f);
}

writecsv("output.csv");
8

  • Kỳ vọng

    function convert($fields) {
        $result = [];
        foreach ($fields as $field) {
            $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
        }
        return $result;
    }
    
    function arr2csv($rows) {
        $fp = fopen('php://temp', 'r+b');
        foreach($rows as $fields) {
            // Convert row data from UTF-8 to Shift-JS
            $fields = convert($fields);
            fputcsv($fp, $fields);
        }
        rewind($fp);
        // Convert CRLF
        $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
        fclose($fp);
        return $tmp;
    }
    
    function writecsv($filename) {
        // Header of csv
        $header = [
            'ID',
            '従業員コード', // Employee code
            '氏名※',       // Name
            'フリガナ',     // Furigana
        ];
        // Sample data from database
        $data = [
            [
                "id" => 1,
                "code" => "A01",
                "name" => "山",
                "furigana" => "カミソヤマ ユニ"
            ],
            [
                "id" => 2,
                "code" => "A02",
                "name" => "上曽山 ゆに",
                "furigana" => "ソ ユニ",
            ],
            [
                "id" => 3,
                "code" => "A03",
                "name" => '上曽山\\" 上曽山',
                "furigana" => "ゆに",
            ],
        ];
        // Prepend header
        array_unshift($data, $header);
        // Open file to write stream data
        $f = fopen($filename, 'w+');
        fwrite($f, arr2csv($data));
        fclose($f);
    }
    
    writecsv("output.csv");
    
    9

  • đầu ra

    ID,従業員コード,氏名※,フリガナ
    1,A01.,山,カミソヤマ ユニ
    2,A02,上曽山 ゆに,ソ ユニ
    3,A03,"上曽山\" 上曽山",ゆに
    
    0

Nguyên nhân kết quả mong đợi không đúng như mong đợi là do hàm

/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (...
  (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
  ...
) {
9 của
ID,従業員コード,氏名※,フリガナ
1,A01.,山,カミソヤマ ユニ
2,A02,上曽山 ゆに,ソ ユニ
3,A03,"上曽山\" 上曽山",ゆに
7 đang được sử dụng sai tiêu chuẩn RFC 4180

Nếu dấu ngoặc kép được sử dụng để bao quanh các trường, thì dấu ngoặc kép xuất hiện bên trong trường phải được thoát ra bằng cách đặt trước nó bằng một dấu ngoặc kép khác

Edit edit back a time

ID,従業員コード,氏名※,フリガナ
1,A01.,山,カミソヤマ ユニ
2,A02,上曽山 ゆに,ソ ユニ
3,A03,"上曽山\" 上曽山",ゆに
1

  • Kỳ vọng

    function convert($fields) {
        $result = [];
        foreach ($fields as $field) {
            $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
        }
        return $result;
    }
    
    function arr2csv($rows) {
        $fp = fopen('php://temp', 'r+b');
        foreach($rows as $fields) {
            // Convert row data from UTF-8 to Shift-JS
            $fields = convert($fields);
            fputcsv($fp, $fields);
        }
        rewind($fp);
        // Convert CRLF
        $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
        fclose($fp);
        return $tmp;
    }
    
    function writecsv($filename) {
        // Header of csv
        $header = [
            'ID',
            '従業員コード', // Employee code
            '氏名※',       // Name
            'フリガナ',     // Furigana
        ];
        // Sample data from database
        $data = [
            [
                "id" => 1,
                "code" => "A01",
                "name" => "山",
                "furigana" => "カミソヤマ ユニ"
            ],
            [
                "id" => 2,
                "code" => "A02",
                "name" => "上曽山 ゆに",
                "furigana" => "ソ ユニ",
            ],
            [
                "id" => 3,
                "code" => "A03",
                "name" => '上曽山\\" 上曽山',
                "furigana" => "ゆに",
            ],
        ];
        // Prepend header
        array_unshift($data, $header);
        // Open file to write stream data
        $f = fopen($filename, 'w+');
        fwrite($f, arr2csv($data));
        fclose($f);
    }
    
    writecsv("output.csv");
    
    9

  • đầu ra

    function convert($fields) {
        $result = [];
        foreach ($fields as $field) {
            $result[] = mb_convert_encoding($field, 'SJIS', 'UTF-8');
        }
        return $result;
    }
    
    function arr2csv($rows) {
        $fp = fopen('php://temp', 'r+b');
        foreach($rows as $fields) {
            // Convert row data from UTF-8 to Shift-JS
            $fields = convert($fields);
            fputcsv($fp, $fields);
        }
        rewind($fp);
        // Convert CRLF
        $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp));
        fclose($fp);
        return $tmp;
    }
    
    function writecsv($filename) {
        // Header of csv
        $header = [
            'ID',
            '従業員コード', // Employee code
            '氏名※',       // Name
            'フリガナ',     // Furigana
        ];
        // Sample data from database
        $data = [
            [
                "id" => 1,
                "code" => "A01",
                "name" => "山",
                "furigana" => "カミソヤマ ユニ"
            ],
            [
                "id" => 2,
                "code" => "A02",
                "name" => "上曽山 ゆに",
                "furigana" => "ソ ユニ",
            ],
            [
                "id" => 3,
                "code" => "A03",
                "name" => '上曽山\\" 上曽山',
                "furigana" => "ゆに",
            ],
        ];
        // Prepend header
        array_unshift($data, $header);
        // Open file to write stream data
        $f = fopen($filename, 'w+');
        fwrite($f, arr2csv($data));
        fclose($f);
    }
    
    writecsv("output.csv");
    
    9

Tuy nhiên, khi sử dụng

/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (...
  (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
  ...
) {
9 với tiêu chuẩn RFC_4180 để ghi ra tệp csv rồi sau đó sử dụng
#define FPUTCSV_FLD_CHK(c) memchr(ZSTR_VAL(field_str), c, ZSTR_LEN(field_str))
// ---> Return:
// A pointer to the first occurrence of value(c) in the block of memory pointed by ptr(field_str).
// If the value is not found, the function returns a null pointer.
2 để đọc lại tệp chính vừa được ghi thì kết quả lại không chính xác

ID,従業員コード,氏名※,フリガナ
1,A01.,山,カミソヤマ ユニ
2,A02,上曽山 ゆに,ソ ユニ
3,A03,"上曽山\" 上曽山",ゆに
4

  • đầu ra

    ID,従業員コード,氏名※,フリガナ
    1,A01.,山,カミソヤマ ユニ
    2,A02,上曽山 ゆに,ソ ユニ
    3,A03,"上曽山\" 上曽山",ゆに
    
    5

Kết quả đọc ra dễ thấy thì dữ liệu lại trở thành 2 hàng trong khi kỳ vọng là 1 hàng mà thôi 🙃

Đây là một lỗi tồn tại trong PHP, không thể sửa được. bạn không thể coi đây là vấn đề coi. 50686 Hiện tại mình cũng không biết sửa lỗi này kiểu gì 🤣