Maison  >  Article  >  développement back-end  >  Comment résoudre le problème des caractères tronqués lors de l'importation de fichiers CSV dans PHP

Comment résoudre le problème des caractères tronqués lors de l'importation de fichiers CSV dans PHP

不言
不言original
2018-07-03 16:15:082730parcourir

Cet article présente principalement la solution au problème des caractères tronqués lors de l'importation de fichiers csv en PHP. Les amis qui en ont besoin peuvent s'y référer

Aujourd'hui, je souhaite principalement écrire une méthode pour importer des fichiers csv en PHP. En fait, je l'ai beaucoup cherché en ligne. Tout peut être mis en œuvre comment importer. Mais j'ai rencontré deux problèmes lors de l'importation. Le premier était que le test présentait des caractères tronqués lors de l'écriture du code sous Windows, puis le problème a été résolu. La seconde est que lorsqu'il a été soumis au système Linux, des caractères tronqués sont apparus à nouveau. Au début, je ne connaissais pas la raison du code tronqué. Au début, j'ai pensé que c'était une erreur dans la soumission du code svn. Finalement, j'ai posé une question dans l'un de mes groupes. Il a dit qu'il avait rencontré une erreur de Windows. Lors de la soumission sous Linux, des erreurs se produisaient toujours au début. Plus tard, la cause s'est avérée être des caractères tronqués. Allons droit au but et voyons comment résoudre ces deux problèmes !

Le problème est résolu :

PHP lit le fichier csv, et le chinois n'est pas lisible sous Windows J'ai tout de suite pensé à une fonction mb_convert_encoding(); ($str, "UTF-8", "GBK"); Alors c'est tout. Bien sûr, vous pouvez également utiliser iconv(); pour définir iconv('GBK', "UTF-8//TRANSLIT//IGNORE", $str); ces deux fonctions peuvent résoudre le problème des caractères tronqués sous Windows ; .

Solution au deuxième problème :

PHP lit les fichiers csv, mais le chinois ne peut pas être lu sous Linux. J'ai trouvé la solution après Baidu et Google

Je viens de l'ajouter une ligne. de code setlocale(LC_ALL, 'zh_CN'); Oui, cela vous aveuglera les yeux. C'est aussi simple que cela, et si vous ne le saviez pas, vous pourriez passer beaucoup de temps à le comprendre.

Explication de la fonction PHP setlocale()

Définition et utilisation

La fonction setlocale() définit les informations régionales (informations régionales).

Les informations régionales sont la langue, la devise, l'heure et d'autres informations pour une zone géographique. Cette fonction renvoie les paramètres régionaux actuels, ou false en cas d'échec.

Les identifiants de région suivants sont couramment utilisés pour la collecte de données :

zh_CN GB2312 
en_US.UTF-8 UTF-8 
zh_TW BIG5 
zh_HK BIG5-HKSCS 
zh_TW.EUC-TW EUC-TW 
zh_TW.UTF-8 UTF-8 
zh_HK.UTF-8 UTF-8 
zh_CN.GBK GBK

Par exemple,
utf-8 : setlocale(LC_ALL, 'en_US.UTF-8′ ) ;
Chinois simplifié : setlocale(LC_ALL, 'zh_CN');

La raison pour laquelle je vous parle de la fonction setlocale() est que lorsque j'ai importé le fichier csv dans le système Linux, les caractères étaient tronqués. s'est produit, y compris l'utilisation des fonctions mb_convert_encoding() et iconv() n'a pas réussi à résoudre le problème final. Enfin, j'ai ajouté cette phrase setlocale(LC_ALL, 'zh_CN'); devant le code au début de l'importation du fichier csv et cela s'est fait facilement. Ensuite, j'ai recherché des informations et j'ai découvert que la fonction fgetcsv() est sensible à. paramètres régionaux. Par exemple, si LANG est défini sur en_US.UTF-8, les fichiers codés sur un seul octet auront des erreurs de lecture, nous devons donc définir la culture. Spécialement partagé avec tout le monde.

J'ai également essayé le code suivant, mais je n'ai pas réussi à le faire fonctionner. Ce sont les paramètres d'en-tête pour générer des fichiers csv. Cela ne fonctionnera peut-être pas pour moi, mais cela pourrait fonctionner pour vous. J'ai donc réglé le problème et fait de mon mieux pour aider mes collègues qui rencontraient des caractères tronqués lors de l'importation de fichiers CSV, car il était vraiment difficile de gérer ce problème lorsqu'il n'y avait pas d'autre moyen. Tout le monde peut l'essayer ! Il y en a toujours un qui vous appartient.

<?php 
$csvContent="csvzero,csvone,csvtwo,csvthree,csvfour,csvfive"; 
header("Content-Type: application/vnd.ms-excel; charset=GB2312"); 
header("Pragma: public"); 
header("Expires: 0"); 
header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); 
header("Content-Type: application/force-download"); 
header("Content-Type: application/octet-stream"); 
header("Content-Type: application/download"); 
header("Content-Disposition: attachment;filename=CSV数据.csv "); 
header("Content-Transfer-Encoding: binary "); 
$csvContent = iconv("utf-8","gb2312",$csvContent); 
echo $csvContent; 
exit; 
?>

Regardons de plus près le code permettant à php d'importer des fichiers csv :

Une brève introduction aux deux fonctions,

Détecté par mb_detect_encoding () Codage de caractères, ou FALSE si le codage de la chaîne spécifiée ne peut pas être détecté.

La fonction fgetcsv() lit une ligne du pointeur de fichier et analyse le champ CSV. Similaire à fgets(), sauf que fgetcsv() analyse la ligne de lecture et trouve les champs au format CSV, puis renvoie un tableau contenant ces champs. fgetcsv() renvoie FALSE en cas d'erreur, y compris lorsque la fin du fichier est rencontrée.

Remarque : depuis PHP 4.3.5, le fonctionnement de fgetcsv() est sécurisé en termes de binaire.

Remarque : Les lignes vides du fichier CSV seront renvoyées sous forme de tableau contenant un seul champ nul et ne seront pas traitées comme une erreur.

Remarque : Cette fonction est sensible aux paramètres régionaux. Par exemple, si LANG est défini sur en_US.UTF-8, les fichiers codés sur un seul octet auront des erreurs de lecture.

Remarque : Si vous constatez que PHP ne peut pas reconnaître les caractères de fin de ligne des fichiers Macintosh lors de la lecture de fichiers, vous pouvez activer l'option de configuration d'exécution auto_detect_line_endings.

<?php 
setlocale(LC_ALL, &#39;zh_CN&#39;); //设置地区信息(地域信息) 
$file = $_FILES[&#39;files&#39;]; 
$file_type = substr(strstr($file[&#39;name&#39;],&#39;.&#39;),1); 
if ($file_type != &#39;csv&#39;){ 
echo "<script type=\"text/javascript\">alert(\"文件格式错误,请重新上传!\"); </script>"; 
exit; 
} 
$handle = fopen($file[&#39;tmp_name&#39;],"r"); 
$file_encoding = mb_detect_encoding($handle); 
if ($file_encoding != &#39;ASCII&#39;){ 
echo "<script type=\"text/javascript\">alert(\"文件编码错误,请重新上传!\"); </script>"; 
exit; 
} 
$row = 0; 
$str=""; 
$sy=""; 
while ($data = fgetcsv($handle,1000,&#39;,&#39;)){ 
$row++; 
if ($row == 0) 
continue; 
$num = count($data); 
for ($i=0; $i<$num; $i++){ 
$str = (string)$data[$i].&#39;|&#39;; 
$str = mb_convert_encoding($str, "UTF-8", "GBK"); //已知源码为GBK,转换为utf-8 
$sy .= $str; //我这里做的比较复杂,是用&#39;|&#39;将csv文件里面的内容用&#39;|&#39;全部拼起来,因为我导入的是商品信息,需要根据用户需 
//要导入的数据去定义哪些数据是需要导入的。 
} 
} 
if ($sy) { $sy = rtrim($sy, &#39;|&#39;); } 
$arr = explode(&#39;|&#39;,$sy); 
$key = array_slice($arr,0,$num); //这个数组就是csv文件里面标题,就是商品id,标题,卖点等等的数据 
$skey = array(); 
$length = array(); 
$co = count($arr); 
$p = $co/$num; //求出要取出的数据的长度 
for($j=0;$j<$p;$j++){ 
$offset=($j-1)*$num; //偏移量,就像分页一样,我这里根据偏移量取出的一个数组就是一个商品的信息。 
if($j==0){ 
$length[] = array_slice($arr,0,$num); 
}else{ 
$length[] = array_slice($arr,$num+$offset,$num);//取出有哪些字段和商品 
} 
} 
$arrtitle = array(); 
$arrfileds = array(); 
$arrtagname = DB::select(&#39;字段标识&#39;, &#39;字段名称&#39;)->from(&#39;字段表&#39;)->fetch_all(); 
foreach ($arrtagname as $value) { 
$arrfileds[$value[&#39;fileds_tags&#39;]] = $value[&#39;fileds_name&#39;]; 
} 
foreach ($fileds as $v) 
{ 
$temarr= explode(&#39;-&#39;, $v); 
if (isset($temarr[0]) && !empty($temarr[0])) { 
if (isset($temarr[1]) && !empty($temarr[1])) { 
if ($temarr[1] == &#39;wenben&#39;) { 
$arrtitle[] = $arrfileds[$temarr[0]].&#39;文本&#39;; 
} 
} else { 
if ($temarr[0] != &#39;pic&#39;) { //是取出字段是图片就给去掉 
$arrtitle[] = $arrfileds[$temarr[0]]; 
} 
} 
} 
} 
$skey = array(); 
$order = array(); 
$order[] = &#39;act_tag&#39;; 
$order[] = &#39;channel_tag&#39;; 
$order[] = &#39;created_time&#39;; 
$order[] = &#39;orderby&#39;; 
$rows =&#39;&#39;; 
$f = $co/$num;//求出有多少件商品 
for($p=0;$p<count($arrtitle);$p++){ 
//这里就是根据自己的需求查出自己需要的数据,通过用户需要的商品字段标识查出表里相对应的英文标识。 
$skey[]= DB::select(&#39;字段标识&#39;)->from(&#39;字段表&#39;)->where(&#39;字段名称&#39;, &#39;=&#39;, $arrtitle[$p])->fetch_row(); 
$rows .= $skey[$p][&#39;字段标识&#39;].&#39;|&#39;; 
} 
if($rows){ $rows = rtrim($rows,&#39;|&#39;); } 
if(!empty($rows)){ $exrows = explode(&#39;|&#39;,$rows); }else{ $exrows = array(); } 
$skeys = array_merge($order,$exrows); 
$count1 = count($skeys); //字段的个数 
if(!empty($length)){ 
for($x=1;$x<$f;$x++){ //求出有多少件商品就的循环多少次 
$orders = array(); 
$orders[] = $act_tag; 
$orders[] = $channel_tag; 
$orders[] = time(); 
$newlen = array_merge($orders,$length[$x]); 
if($count1 !== count($newlen)){ //如果商品字段的长度和商品的长度不等就证明用户有哪个字段没录入 
$newrs = array(); 
echo "<script type=\"text/javascript\">alert(\"<font color=#f00;>".&#39;请检查第,&#39;.($x-1).&#39;件商品!&#39;.&#39;导入失败!&#39;."</font>"); </script>"; 
fclose($handle); 
exit(); 
}else{ //start 
$arrimport = array_combine($skeys,$newlen); //如果两个数组是相等的我就合并数组,并把导入csv里面的日期改为时间戳存储到数据库 
if(!empty($arrimport[&#39;start_time&#39;])){ $sta = strtotime($arrimport[&#39;start_time&#39;]); }else{ $sta=(int)0; } 
if(!empty($arrimport[&#39;end_time&#39;])){ $end = strtotime($arrimport[&#39;end_time&#39;]); }else{ $end=(int)0; } 
$arrtime=array(&#39;start_time&#39;=>$sta,&#39;end_time&#39;=>$end); 
if(!empty($arrimport[&#39;start_time&#39;]) && !empty($arrimport[&#39;end_time&#39;])){ 
$newrs=array_merge($arrimport,$arrtime); 
}else{ 
$newrs = array(); 
echo "<script type=\"text/javascript\">alert(\"<font color=#f00;>".&#39;请检查第,&#39;.($x-1).&#39;件商品!&#39;.&#39;导入失败!&#39;."</font>"); </script>"; 
fclose($handle); 
exit(); 
} 
if(count($skeys) == count($newrs)){ 
DB::insert(&#39;商品表&#39;, array_values($skeys)) 
->values(array_values($newrs)) 
->execute(); 
} 
} //end 
} 
} 
if($row-1==(int)0){ 
echo "<script type=\"text/javascript\">alert(\"<font color=#f00;>".&#39;您导入的商品为空!&#39;."</font>"); </script>"; 
}else{ 
echo "<script type=\"text/javascript\">alert(\"<font color=#f00;>".&#39;成功导入&#39;."<font color=#f00;>".($row-1)."</font>".&#39;件商品!&#39;."</font>"); 
} 
fclose($handle); 
} 
?>

Ce qui précède est le processus d'importation CSV que je dois effectuer pour mon travail. Il peut être différent de votre méthode d'importation, mais certains codes vous seront toujours utiles !

Ce qui suit est une simple importation :

<form enctype="multipart/form-data" action="import.php" method="POST"> 
导入模板 
<label for="文件选择">文件选择:</label><input name="csv_goods" type="file" /> 
<input type="submit" value="导入" name="import" /> 
</form> 
<?php 
if (isset($_POST[&#39;import&#39;])){ 
$file = $_FILES[&#39;csv_goods&#39;]; 
$file_type = substr(strstr($file[&#39;name&#39;],&#39;.&#39;),1); 
// 检查文件格式 
if ($file_type != &#39;csv&#39;){ 
echo &#39;文件格式不对,请重新上传!&#39;; 
exit; 
} 
$handle = fopen($file[&#39;tmp_name&#39;],"r"); 
$file_encoding = mb_detect_encoding($handle); 
// 检查文件编码 
if ($file_encoding != &#39;ASCII&#39;){ 
echo &#39;文件编码错误,请重新上传!&#39;; 
exit; 
} 
$row = 0; 
while ($data = fgetcsv($handle,1000,&#39;,&#39;)){ 
//echo "<font color=red>$row</font>"; //可以知道总共有多少行 
$row++; 
if ($row == 1) 
continue; 
$num = count($data); 
// 这里会依次输出每行当中每个单元格的数据 
for ($i=0; $i<$num; $i++){ 
echo $data[$i]."<br>"; 
// 在这里对数据进行处理 
} 
} 
fclose($handle); 
} 
?>

Ce qui précède est l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'apprentissage de chacun. Pour en savoir plus. contenu connexe, veuillez faire attention à PHP Chinese net !

Recommandations associées :

Introduction au traitement php de l'interception de chaînes chinoises (mb_substr) et obtention du nombre de caractères dans les chaînes chinoises

Introduction à l'interface d'appel curl encapsulée PHP et aux fonctions communes

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn