질문을 삭제하지 말아주세요.!
 
1
0
-1


A-DB 에 상품 테이블에 있는 내용을 B-DB 전송하는 업무 입니다. 상품을 읽어서 다른 DB에 insert 합니다.

A-DB 의 컬럼은 UTF-8 이고 B-DB 의 컬럼은 EUC-KR 입니다.

다만 A-DB 의 경우 웹상에서 crwal 한데이타가 들어 있습니다.




<에러내용>

[2017-07-10 22:02:53] local.ERROR: sendProductOnTarget@BalaanOldKidDatabaseExporter:SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xA1\xC621 K...' for column 'goodsnm' at row 1 (SQL: insert into `gd_goods` (`goodsnm`, `size_type`, `origin`, `maker`, `keyword`, `shortdesc`, `longdesc`, `mlongdesc`, `img_i`, `img_s`, `img_m`, `img_l`, `img_x`, `img_y`, `img_z`, `img_mobile`, `memo`, `regdt`, `optnm`, `totstock`, `useblog`, `inpk_dispno`, `inpk_prdno`, `inpk_regdt`, `inpk_moddt`, `sales_range_start`, `sales_range_end`, `borabora_sku_id`, `product_id`, `goods_price`) values (N��21 KIDS Sweatshirt,  , , N��21 KIDS, , BK-25664, {'Details': '[, Color: Grey, , Descrirption: Neoprene sweatshirt with round neckline and logo printed on the chest. Characteristic short cut and little back contrasting button., , Details: 95%Cotton 5%Elastane. Machine wash., ]', 'Size_Fit': 'No size_fit stated'}, {'Details': '[, Color: Grey, , Descrirption: Neoprene sweatshirt with round neckline and logo printed on the chest. Characteristic short cut and little back contrasting button., , Details: 95%Cotton 5%Elastane. Machine wash., ]', 'Size_Fit': 'No size_fit stated'}, , , , , , , , , , 2017-07-10 22:02:53, 사이즈, 1, , , , 2017-07-10 22:02:53, 2017-07-10 22:02:53, 0, 0, 25664, 11389, 95.901639))

     B-DB 에 상품 내용을 넣을때 goodsnm(상품) 컬럼에 데이타를 넣을때 Incorrect String Value 라고 에러가 발생합니다.


위와 같이 상품명이 저렇게 특수문자가 들어가면 에러가 발생합니다.

UTF-8 및 EUC-KR 캐릭터맵에 모두 존재하는 문자임 에도 불구하고 iconv 가 변환을 하지 못합니다.



A-DB 에서는 name 컬럼 입니다.


 B-DB 에서는 goodsnm 컬럼입니다.



코드는 아래와 같습니다.


public function sendProductOnTarget($product_id)
{

try {
DB::beginTransaction();
$product = Product::with(['shop','shopurl'])->find($product_id);

//최대 재고 갯수 찾기
$max_stock = BoraHelper::findMaxStockInJson($product->options);

//판매가
$goods_price = BoraHelper::getGoodsPrice($product->options);

//소비자가
$goods_consummer = BoraHelper::getGoodsConsummer($product->options);

//옵션명
$optnm = BoraHelper::getOptName($product->options);

//gd_goods 의 option_value 컬럼
$option_value = BoraHelper::getOptionValue($product->options);


//$encoding = iconv_get_encoding($product->brand_name);
// 여기서 iconv 를 이용해서 변환을 해도 DB에 안들어 가네요
$brand_name = iconv("UTF-8", "euc-kr//IGNORE", $product->brand_name);
$goodsnm = iconv("UTF-8", "euc-kr//IGNORE", $product->name);
$long_DESC = iconv("UTF-8","euc-kr//IGNORE", $product->long_DESC);


//$mlong_DESC = iconv("UTF-8","cp949//IGNORE", $product->long_DESC);
//$goodsnm = mb_convert_encoding($product->name, "UTF-8", "CP949");
//$long_DESC = mb_convert_encoding($product->long_DESC, "UTF-8", "CP949");
//$brand_name= mb_convert_encoding($product->brand_name, "UTF-8", "CP949");
//Log::info(implode(',',$product->img_urls));
// $long_DESC = iconv("UTF-8", "EUC-KR//TRANSLIT", $product->long_DESC);
//$long_DESC = base64_encode($product->long_DESC);
//$long_DESC = base64_decode();
//$long_DESC = iconv("UTF-8","ISO-8859-1//TRANSLIT", $long_DESC);


$BalaanOldKid = BalaanOldKid::create([
'goodsnm' => $goodsnm,
'size_type' => ' ',
'origin' => '',
'maker' => isset($brand_name) ? $brand_name : '',
'keyword' => '',
'runout' => '',
'shortdesc' => ($this->sub_mall_type == 'adult') ? 'BA-' . $product->sku_id : 'BK-' . $product->sku_id,
'longdesc' => isset($long_DESC) ? $long_DESC : '',
'mlongdesc' => isset($long_DESC) ? $long_DESC : '',
'tax' => isset($product->is_taxation) ? $product->is_taxation : '1',
'delivery_type' => isset($product->delivery_type) ? $product->delivery_type : '0',
'img_i' => '',
'img_s' => '',
'img_m' => '',
'img_l' => '',
'img_x' => '',
'img_y' => '',
'img_z' => '',
'img_mobile' => '',
'memo' => '' ,
'regdt' => Carbon::now()->toDateTimeString(),
'optnm' => isset($optnm) ? $optnm : '',
'option_value' => isset($option_value) ? $option_value : '',
'totstock' => isset($max_stock) ? $max_stock : '0',
'useblog' => '',
'inpk_dispno' => '',
'inpk_prdno' => '',
'inpk_regdt' => Carbon::now()->toDateTimeString(),
'inpk_moddt' => Carbon::now()->toDateTimeString(),
'sales_range_start' => '0',
'sales_range_end' => '0',
'borabora_sku_id' => isset($product->sku_id) ? $product->sku_id : '',
'product_id' => isset($product->id) ? $product->id : '',
'goods_price' => isset($goods_price) ? $goods_price : 0,
'goods_supply' => 500000,
'goods_consummer' => isset($goods_consummer) ? $goods_consummer : 0,
]);

$product->targets()->sync([
($this->sub_mall_type == 'adult') ? 5 : 6
=> ['target_enabled' => true,
'target_product_id' => $BalaanOldKid->goodsno,
'created_at' => Carbon::now()->toDateTimeString()],
]);

if (!$BalaanOldKid && !$product) {
Log::error('sendProductOnTarget@BalaanOldKidDatabaseExporter:' . '[rollback][' . $product->id . '][' . $product->name . ']');
throw new ModelNotFoundException;
}

DB::commit();

//이미지 경로 컬럼에서 불필요한 문자 제거
$images = BoraHelper::parseImgPathTrait($product->img_urls);

//이미지 이름을 고도몰 goodsno 컬럼(key column) 을 포함하는 이름으로 변경 => 고도몰에서 이미지 경로로 변경
$url_prefix = 'http://balaan3.godo.co.kr/shop/data/goods/';
$target_with_pivot = Product::find($product_id)->targets()->where('name','=',$this->target)
->where('sub_mall_type','=',$this->sub_mall_type)
->withPivot('target_product_id')
->first();
$target_product_id = $target_with_pivot->pivot->target_product_id;

$images = BoraHelper::imageNameUrlToId($images,$target_product_id,$url_prefix);

//고도몰 이미지 경로 구분자 넣어줌
$img_full = implode('|',$images);

$img_conn=BalaanOldKid::where('product_id','=',$product_id)->first();

$img_conn->img_i = isset($images[0]) ? $images[0] : '';
$img_conn->img_s = isset($images[0]) ? $images[0] : '';
$img_conn->img_m = $img_full;
$img_conn->img_l = $img_full;
$img_conn->save();


Log::info('sendProductOnTarget@BalaanOldKidDatabaseExporter:' . '[success][' . $product->id . '][' . $product->name . ']');
return collect([
'result_code' => true,
'erro_message' => 'null',
]);

} catch (Exception $ex) {
Log::error('sendProductOnTarget@BalaanOldKidDatabaseExporter:' . $ex->getMessage());
DB::rollBack();
return collect([
'result_code' => 'false',
'erro_message' => $ex->getMessage(),
]);
}

}


고수님들의 의견 간절히 기다립니다.

감사합니다.




    CommentAdd your comment...

    7 answers

    1.  
      5
      4
      3

      아래의 코드로 오류를 똑같이 구현했습니다.

      전반적으로 문제가 될 부분이 보이지 않아서 마지막으로 가장 의심스러운 부분이었던 DB 접속시 DNS 의 charset을 euc-kr로 바꿔보니 문제가 해결되는 것을 확인했습니다.

      mysql:dbname={$dbname};host={$host};charset=euckr


      <?php

      $pdo = pdodb();


      $c = "N\u{00b0}21 KDIS";

      $name = mb_convert_encoding($c, 'EUC-KR', 'UTF-8');


      $stmt = $pdo->prepare("INSERT _tt SET name = :name");

      $stmt->execute([':name' => $name]);




      테스트한 테이블 스키마

      CREATE TABLE `_tt` (

        `name` varchar(100) NOT NULL,

        PRIMARY KEY (`name`)

      ) ENGINE=InnoDB DEFAULT CHARSET=euckr;



      1. dangtong

        헉~~~!!!!!!!!!!

        테스트 해보겠습니다. ~~~~~~

        라라벨에서 어덯게 해야할지 모르겠지만..일단 찾아보고 테스트 해보겠습니다.

        감사합니다.~~~~~~!!!!!!!!!!!!!!!

      2. dangtong

        됩니다. 감사합니다. ~~!!!!!!!


        'gdshop' => [
        'driver' => 'mysql',
        'host' => env('GD_DB_HOST', '127.0.0.1'),
        'port' => env('GD_DB_PORT', '3306'),
        'database' => env('GD_DB_DATABASE', 'forge'),
        'username' => env('GD_DB_USERNAME', 'forge'),
        'password' => env('GD_DB_PASSWORD', ''),
        'unix_socket' => env('GD_DB_SOCKET', ''),
        'charset' => 'euckr',
        'collation' => 'euckr_korean_ci',
        'strict' => true,
        'prefix' => '',
        'strict' => true,
        'engine' => null,
        ],

        말씀하신데로 바꾸니깐 잘되네요

        dbconnection 에서 utf-8 에서 euc-kr 로 바꿔주니깐. 잘되네요

        감사합니다. ~~~!!!!

        정말 감사합니다. ^^;

      3. dangtong

        정말 기본부터 다시 배워야 겠다는 생각이 드네요 ㅜㅜ

      4. 박민권

        근데 이미 utf-8로 접속하신 상태이시잖아요.

        제가 아래와 같이 utf-8로 접속한 상태에서 잠시 euc-kr로 전환하고 동작이 성공하는 것도 확인했습니다.

        <?php
        $pdo->exec('SET NAMES euckr');
        
        $stmt = $pdo->prepare("INSERT _tt SET name = :name");
        
        $stmt->execute([':name' => $name]);

        평소에는 UTF-8로 하시다가 필요한 경우에만 EUC-KR로 전환해서 작업 후 다시 UTF-8로 바꾸시는게 좋을 것 같습니다.

      CommentAdd your comment...
    2.  
      2
      1
      0

      박민권님이 답은 내신 듯 하고,

      mysql euckr 에 문자가 있는지는 gui 클라이언트에서 이렇게 쿼리해보면 됩니다.

      set names utf8;
      SELECT _EUCKR x'a1c6';

      1. dangtong

        오넵 ...좋은정보 감사합니다.

      CommentAdd your comment...
    3.  
      2
      1
      0

      iconv 대신에 mb_convert_encoding() 을 써보시면 어떨까요?

      http://php.net/manual/kr/function.mb-convert-encoding.php

      mb_convert_encoding() 으로도 안된다면 인코딩 문제니까 특별히 코드에 문제가 있을 것 같지는 않으니 소스 코드 보다는 오류가 나는 데이터의 레코드 한줄 원본 데이터가 있어야 문제의 원인을 테스트 해볼 수 있을 것 같습니다.

      1. dangtong

        그건 써봤는데, 특수문자가 완전히 다른문자로 치환됩니다.

      CommentAdd your comment...
    4.  
      2
      1
      0

      utf-8 에서 해당 문자열 json_encode() 해서 보여주세요.

      CommentAdd your comment...
    5.  
      1
      0
      -1

      json_encode 로 하니깐

      [2017-07-10 22:56:40] local.INFO: json:"N\u00b021 KIDS"

      이렇게 나옵니다.

      1. dangtong
        $json = json_encode($product->brand_name);
        Log::info('json:'.$json);

        참고로 이렇게 했습니다.

      2. 박민권

        제가 아래와 같이 간단히 테스트를 해봤는데 변환에 문제가 없습니다.

        말씀하신대로 EUC-KR의 문자 테이블(http://www.fileformat.info/info/charset/EUC-KR/list.htm)에 대응되는 문자가 존재하는 것도 확인했고 실제 변환되어서 출력시 문제가 없는 것도 확인했습니다.

        <?php

        $c = "\u{00b0}";

        echo mb_convert_encoding($c, 'EUC-KR', 'UTF-8');


        혹시나 싶어서 말씀을 드리는데 저에게 답변하신

        "그건 써봤는데, 특수문자가 완전히 다른문자로 치환됩니다."와 "iconv 가 변환을 하지 못합니다."라고 하셨는데요.

        잘못 확인하신 것은 아니신지요? UTF-8 문자가 표시되는 환경에서 EUC-KR로 변환해서 출력을 하셨다면 깨져서 나오게됩니다. 출력을 확인하시는 환경에서 EUC-KR로 확인하셔야 합니다.


        정리하자면 iconv나 mb_convert_encoding 을 사용하여 인코딩을 변환하는 것은 문제가 없는 것 같으니 DB 와 관련된 코드와 환경을 확인해야 할 것 같습니다.

      3. dangtong


        위의 문자열에서 "째" 가들어간것은 mb_convert_encoding 을 썻을때입니다.

        그리도 KIDS 정상적으로 나온것은 substr 로 BOM을 제거 했을때 입니다.

        위캡쳐 화면은 B-DB에서 조회한 결과 입니다.

      4. dangtong

        저도 이해가 안되는데, iconv 는 맵핑되는 문자가 없을때 에러가 나는데, 분여 맵핑 되는 문자가 있는데 에러가 난다는 것입니다.

        그렇다면 위에서 말씀하신 EUC-KR 환경이라는게 혹시 LARAVEL의 언어 설정과 관련이 있는지요?

        Laravel설정이 UTF-8 이라서 그런거라고 봐야 하나요?

      CommentAdd your comment...
    6.  
      1
      0
      -1

      내일이 서비스 오픈이라고 저한테 급히 연락이 와서요. 서로 돕고 살아야 된다는 마음에 도움 요청드렸습니다.

      제 아이디어는 안될 수도 있지만, 급한대로 DB INSERT할 때 앞에 붙어 있는 BOM(Byte Order Mark)를 제거해 보시라고 말씀드려봅니다. 

      $goodsnm = substr(iconv("UTF-8", "euc-kr//IGNORE", $product->name), 5);

      1. dangtong

        그렇게 하면 해당 row 가 넘어 갑니다.

        하지만 변환이 안되서...브랜드명에 특수문자가 많아서요...

        분명이 해당 특수문자들이 UTF-8 및 EUC-KR 맵에 있는 문자있데..

        변환할 방법이 없을까요?

      CommentAdd your comment...
    7.  
      1
      0
      -1

      박민권 님 호출.

        CommentAdd your comment...