2013-12-20 2 views
2

블로그, Google 및 스택 오버플로를 통해 많은 검색을 수행했습니다. 나는 아직 내 문제에 대한 해결책을 찾지 못했다.Excel에서 CSV 파일을 처리하여 MySQL에 "잘못된 문자열 값"오류 발생

내 PHP 응용 프로그램에서는 사용자가 시스템에 데이터를 가져 오기 위해 채울 csv 템플릿 (헤더 포함)을 다운로드 할 수 있습니다. 가져 오는 행 중 하나에 대해 CSV 파일에서 특수/외래 문자 (Umlaut, Acute, Grave)를 사용하지 않으면 모든 것이 효과적입니다.

사용자가 CSV를 다운로드 한 다음 Excel에서 열 때 (사무실이 설치된 대부분의 시스템에서 기본값). 모든 파일을 가져올 때 파일에 추가하고 Excel에서 저장을 클릭하면 올바르게 인코딩되지 않은 것을보고 이해 한 것입니다. 일단 그들이 변경된 파일을 업로드하고 PHP가 CSV를 통해 MySQL 데이터베이스에 데이터를 삽입하는 것을 반복하면 "레코드 1366을 업데이트 할 수 없습니다 : 1 행의 'rawContents'열에 대해 잘못된 문자열 값 : '\ x9Arn 's ...' .

"Excel을 사용하지 마십시오"와 같은 해결책은 옵션이 아닙니다. 업로드 된 파일을 받아 인코딩이 UTF-8로 설정되어 있는지 확인하여 데이터베이스에 올바르게 읽도록하는 솔루션을 찾고 있습니다. 현재 예외를 잡는 중입니다. "Incorrect string value"오류가 있으면 사용자에게 잘못된 데이터가 있다는 메시지를 출력하고 인코딩을 확인한 다음 다시 시도하십시오. 내가 상관없이 그들의 CSV를 처리 할 수 ​​있고 잘못된 데이터가있는 행 (읽을 수없는 경우)은 무시되고 "오류 행"(잘못된 사용자 입력이 포함 된 행)에 저장됩니다. 유효성 검사를 통해 열을 볼 수 있음) 어떤 행을 볼 수 있으며, 오류가있는 행만 포함하는 다른 CSV를 내보낼 수 있습니다.

너무 혼란스럽지도 불분명하지 않기를 바랍니다. 인코딩을 해결하고 그 좋은 거라고 저장하는 올바른 문자 인코딩을 얻을 수있는 방법이 있다면

function utf8_clean($str, $ignore = true) 
{ 
    return iconv('UTF-8', 'UTF-8//' . (($ignore) ? 'IGNORE' : 'TRANSLIT'), $str); 
} 

function contains_non_utf8($str) 
{ 
    return (serialize($str) != serialize(utf8_clean($str))); 
} 

: 나는 다음을 사용하여 비 UTF8 문자가있는 행을 감지 할 수있는 방법을 발견했다. 두 번째 옵션은 내가 언급 한 "오류 행"입니다. 올바른 인코딩으로 가져올 수없는 경우 해당 오류를 수정하기 위해 CSV 파일 "오류 행"을 내보내기 위해 저장하고 싶습니다. 하지만 CSV에서 오류 행으로 내보낼 수 있도록 행의 "원시"포함 된 저장할 수있는 방법을 모르겠습니다.

여기에 대해 내가 할 수있는 것에 아이디어를 던져 주시기 바랍니다. 필자가 생각한 한 가지 옵션은 템플릿 파일에 설정된 경우 저장시 UTF-8 인코딩을 유지하는 것으로 보이기 때문에 Excel 파일 가져 오기를 지원하는 것이지만 여전히 CSV를 지원하는 방법을보고 싶습니다.


나는 매우 효과가 있지만뿐만 아니라이 길에 몇 가지 문제로 실행 보인다 데이터베이스에 데이터를 가져 오기 위해 "MacRoman도"사용하려고 시도하고있다.

가 지금 내가 유사한 시도/catch 문이있어 : 이것이하는 일은이 오류 코드 실패 할 경우 시도, 데이터베이스에 CSV 데이터를 저장하는 것입니다

try { 
    $this->saveImportRow($array) 
} catch (Exception $e) { 
    if ($e->getCode() === 1366) { 
     $dbClass->execute('SET NAMES \'macroman\''); 
     $this->saveImportRow($array) 
     $dbClass->execute('SET NAMES \'utf8\' COLLATE \'utf8_unicode_ci\''); 
    } 
} 

를 1366 다음 다시 시도합니다 저장하기 전에 "매크로 맨 (macroman)"을 사용하십시오. 이것은 제대로 작동하는 것으로 보이며 Excel에서 열어 저장 한 CSV 파일을 가져올 수 있지만 특수 문자 (예 : ö)가 포함되어 있고 Excel에서 적절한 인코딩으로 저장하지 않는 CSV 파일을 가져올 수 있습니다. 또한 UTF-8로 인코딩되고 특수 문자 (예 : ö)가 포함 된 CSV 파일을 허용합니다.

이제 데이터를 가져 와서 가져 오기 처리 중입니다.

데이터가 저장되면 매핑을 위해 배열에 저장되며 (키는 값이 속한 데이터베이스 열임)이 배열은 직렬화되어 parsedData로 데이터베이스에 저장됩니다. 문제는 해당 데이터의 비 직렬화입니다. 행이 utf-8을 사용하여 삽입되었을 때 데이터가 평소와 같이 작동 할 때 데이터의 직렬화를 해제하는 데 문제가 없지만 CSV 파일에서 인코딩이 적절하지 않은 경우 데이터베이스에 특수 문자를 가져 오는 새로운 변경으로 " 매크로먼. "

행을 선택하기 전에 "macroman"을 사용하여 삽입 된 행이 작동하고 직렬화 할 수 없지만 UTF-8 삽입 행이 직렬화 할 수없는 경우 "SET NAMES '매크로를 사용해야합니다. 매우 실망합니다. 어떤 아이디어?

나는 내 목표가 정말로 인코딩이 적절하지 않다는 것을 사용자에게 알리는 것을 알고 있지만 흥미 롭다고 생각했다. 나는 그들을 데이터베이스에 가져올 수 있었고, 매크로 언를 사용하여 올바르게 가져올 수 있었다. 업로드 된 적절한 인코딩 된 CSV입니다. 어쩌면 내가 가져 오기 자체를 "macroman"인지 아닌지 알기 위해 만들 필요가 있습니다. 그 이유는 macroman으로 CSV 파일에 행을 1 개 삽입해야하고 전체 파일이 잘못 인코딩되었다고 가정 할 수 있기 때문입니다. 또는 잘못된 인코딩을 사용하여 행을 특수 문자로 표시하고 해당 인코딩을 수정하도록 알릴 수 있음을 알았 기 때문에 목표가 일종의 것으로 만났습니다. 그러나 나는 모든 사용자가 더 많은 접근 방식을 선호한다고 확신한다.

가져 오기 프로세스가 완전히 다시 생각해 볼 필요가 있을지 모르지만 확실하지 않습니다. 더 많은 의견/솔루션/아이디어 크게 감사하겠습니다.


전환 및 많은 더 많은 연구와 고민 후 나는 맥 로마 또는 인코딩 윈도우 1252 (기본 인코딩, Excel에서 CSV 파일을 열 변경 및 저장)의 여부를 검출에 대한 몇 가지 추론을 가로 질러왔다. 문자열이 다음 바이트 중 하나가 다음 MacRoman도 가정 포함 * 경우 :

저는 여기까지 온 논리의 0x8e, 즉, 0x8f를, 0x9A, 0xA1, 0xA5, 0xA8, 0xD0, 0xD1, 0xD5, 0xE1 *이 경우] 문자열에 다음 바이트 중 하나가 포함 된 경우 Windows-1252를 가정합니다. contains_non_utf8 함수를 사용하여 문자열에 처음 문자가있는 경우를 감지합니다 (예 : s)를 UTF-8로 인코딩하지 않은 다음 MacRoman 또는 Windows-1252인지 여부를 감지하는 기능을 제공합니다. 그 다음에 나는 UTF-8 유효한 문자열을 받기 위해 iconv ('MACROMAN', 'UTF-8', $ str) 또는 iconv ('Windows-1252', 'UTF-8', $ str) .

는 여기가 검출 바이트 또한

function isMacRomanEncoded($str) { 
    $testBytes = array(0x8E, 0x8F, 0x9A, 0xA1, 0xA5, 0xA8, 0xD0, 0xD1, 0xD5, 0xE1); 
    foreach ($testBytes as $testByte) { 
     if (mb_strpos($str, chr($testByte)) !== false) { 
      return true; 
     } 
    } 
    return false; 
} 

function isWindows1252Encoded($str) 
{ 
    $testBytes = array(0x92, 0x95, 0x96, 0x97, 0xAE, 0xB0, 0xB7, 0xE8, 0xE9, 0xF6); 
    foreach ($testBytes as $testByte) { 
     if (mb_strpos($str, chr($testByte)) !== false) { 
      return true; 
     } 
    } 
    return false; 
} 

에 대한 해낸 두 가지 새로운 기능의 또 다른 생각입니다 contains_non_utf8에 해당하는 경우 다음 또한 MacRoman도/윈도우 1252과 더 시도 할 다음 "mb_detect_encoding"제을 탐지.

+0

Mac에서는 Excel에서 인코딩하는 것이 Mac Roman이므로 iconv는 UTF-8로 변환 할 수있었습니다. 지금 Windows PC 설치 프로그램을 통해 Excel에서 어떤 인코딩 유형을 사용하는지 테스트합니다 (기본적으로 Windows-1252라고 가정). 유일한 문제는 지금까지 시도한 모든 감지가 인코딩 유형을 감지 할 수 없기 때문에 어떤 인코딩이 사용되었는지 알지 못하는 것입니다. – MasterEthan

답변

0

내가 끝내기 시작한 해결책을 가지고 내 자신의 질문에 대답 할 것입니다.

위의 질문에서 마지막으로 추가 한 내용은 거의 최종 해결책입니다.

때 내가 문자열에 is_non_utf8 검사를 사용하는 CSV에서 데이터를 읽고 나는 다음과 같은 논리를 실행하는 경우는 true : 를 * 문자열이 다음 MacRoman도 가정 다음 바이트 중 하나가 포함되어있는 경우 : 0x8e, 즉, 0x8f를, 0x9A, 0xA1을, 문자열이 다음 바이트를 포함하는 경우 0xA5, 0xA8는 0xD0는 0xD1는 0xD5는 0xE1 *이 다음 가정 윈도우 1252 : 0x92,에 0x95, 0x96을, 0x97, 0xAE, 0xB0, 0xB7, 0xE8, 0xE9, 0xF6

위의 경우 중 하나가 참/가정하면 iconv를 사용하여 문자열을 UTF-8로 변환합니다. 그렇지 않다면 나는 문자열에 아무 것도하지 않고 평소대로 계속합니다.

따라서 contains_non_utf8 함수를 사용하여 문자열에 utf-8로 인코딩되지 않은 문자가있는 경우이를 감지하고 MacRoman 또는 Windows-1252인지 여부를 감지하는 함수. 그 다음에 나는 UTF-8 유효한 문자열을 받기 위해 iconv ('MACROMAN', 'UTF-8', $ str) 또는 iconv ('Windows-1252', 'UTF-8', $ str) .

삽입시 삽입 쿼리를 try/catch 문으로 래핑했습니다. catch에서 오류 코드 "1366"을 찾았습니다. 데이터가 제외되도록 데이터 행을 업데이트하지만 행을 오류 메시지와 함께 오류 레코드로 표시합니다. 이 방법으로는 가져올 수없는 데이터를 가진 사용자에게 다시 내보내기를 제공 할 수는 없지만 줄 번호가 제공되므로 업로드 파일에서 실패한 레코드를 확인할 때 다시 볼 수 있습니다. 수입.

그래서 당신은 그것을 가지고 있습니다. 이것은 사용자가 템플릿 CSV를 다운로드하고 Excel (Mac 또는 Windows)에서 열고 움라우트 (또는 UTF-8로 사용할 수있는 다른 외래 문자)가 포함 된 데이터를 추가하고 저장을 클릭 한 다음 파일을 선택하는 방법입니다. 파일 html 입력, 제출 및 가져 오기가 성공적으로/올바르게 수행됩니다. 다음 달에 사용 예정이므로 다른 것이 나오면이 티켓을 해당 세부 정보로 업데이트해야합니다.

여기 내가 사용하는 기능입니다 :

function isMacRomanEncoded($str) { 
    $testBytes = array(0x8E, 0x8F, 0x9A, 0xA1, 0xA5, 0xA8, 0xD0, 0xD1, 0xD5, 0xE1); 
    foreach ($testBytes as $testByte) { 
     if (mb_strpos($str, chr($testByte)) !== false) { 
      return true; 
     } 
    } 
    return false; 
} 

function isWindows1252Encoded($str) 
{ 
    $testBytes = array(0x92, 0x95, 0x96, 0x97, 0xAE, 0xB0, 0xB7, 0xE8, 0xE9, 0xF6); 
    foreach ($testBytes as $testByte) { 
     if (mb_strpos($str, chr($testByte)) !== false) { 
      return true; 
     } 
    } 
    return false; 
} 

여기에 언급 된 catch 문의 예 :

try { 
    return $this->saveImportRow($array) 
} catch (Exception $e) { 
    if ($e->getCode() === 1366) { 
     $array['dataColumn'] = null; 
     $array['status'] = '2'; // 2 = Error 
     $array['msg'] = 'Row contained invalid characters'; 
     return $this->saveImportRow($array) 
    } 
    throw $e; 
} 

질문 (또는 추가 입력)이 있으면 알려주세요.

감사합니다.

1

내 경험에 의하면 여기서 템플릿은 csv 파일에 BOM (Byte Order Mark)이 없으므로 Excel에서 기본 인코딩으로 기본 설정됩니다.

PHP로 템플릿을 만들고 (파일 truley의 내용이 utf-8이라고 확신하는 경우) csv 파일이 텍스트이기 때문에 Excel에서 파일이 올바르게 열리도록 할 수 있습니다 (Windows의 경우). 적어도) 다음과 같은 사용 : 당신은 또한 템플릿이 방법을 편집 할 수 있도록 또한, 당신을 위해 텍스트 파일에 BOM을 추가합니다

$filecontents = chr(239) . chr(187) . chr(191) . $filecontents; 

지금 당신이 윈도우에있는 것으로 추정, 메모장 ++.

가져 오기 - 게시물 Excel의 잠재적 인 인코딩 문제를 테스트하는 또 다른 유용한 방법은 메모장에서 파일을 열고 utf-8로 저장 한 다음 가져 오기가 문제를 해결하는지 확인하는 것입니다.

이제 Excel을 저장할 때 사용자가 인코딩을 변경하지 않으면 utf-8이 기본값으로 설정되어 php fine으로 읽혀집니다.

+0

이전에 BOM을 발견했으며 Windows Excel에서도 작동하지만 OS X Excel에서는 작동하지 않습니다. OS X에서는 첫 번째 열/행의 문서 자체에 특수 문자를 추가합니다.메모장을 사용하여 utf-8로 저장하는 솔루션은 사실이지만 사용자가 아무 것도 할 필요없이 간단히 템플릿을 다운로드 (일반적으로 Excel), 입력 데이터 저장, 저장 등의 방법으로 찾을 수 있도록 노력하고 있습니다. 가져 오기/업로드. – MasterEthan

+0

데이터를 저장하기 전에이 mysql 쿼리 "SET NAMES 'macroman'"을 사용하는 것이 발견되었지만 저장된 직렬화 된 데이터의 일부인 경우 올바르게 데이터를 직렬화 해제하지 않았습니다. – MasterEthan

관련 문제