728x90

스마트폰 앱을 다운로드하는 코드이다.

파일 다운로드하는 코드에 스마트폰 장치를 인식하는 코드와 접목하여 어플을 다운로드 하도록 한다.

파일을 직접 접속하는 경우에는 동작하지 않도록 $_SERVER['HTTP_REFERER'] 기능을 사용하여 체크한다.

좀 더 정교하게 보완하는 것도 좋을 것이다.


<?php
require_once "deviceChk.php"; // 접속 Device 체크
if($mtype > 2) { // PC에서 접속하면 아래 코드 미 실행
    echo 'no access';
    exit;
}
require_once 'config/config.php';
if($mtype==2){
    $url='<a href="appDown.php">ABC <br/>어플 다운로드</a>';
}
?>

<!DOCTYPE html>
<html lang="ko">
<head>
  <title>ABC App 다운로드</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <div class="row align-items-center justify-content-center" style="height:60vh;">
        <div>
            <h4><?php echo $url;?></h4>
        </div>
    </div>
</div>
</body>
</html>

=== appDown.php ===

<?php
if(!isset($_SERVER['HTTP_REFERER'])) {
    echo 'direct access denied!';
    exit;
}

require_once "deviceChk.php"; // 접속 Device 체크
if($mtype==2){ // Android 폰 이면
    require_once 'config/config.php';
    $filepath = './files/'.$hostAbb.'.apk';
    $filesize = filesize($filepath);
    $path_parts = pathinfo($filepath);
    $filename = $path_parts['basename'];
    $extension = $path_parts['extension'];

    header("Pragma: public");
    header("Expires: 0");
    header("Content-Type: application/octet-stream");
    header("Content-Disposition: attachment; filename='$filename'");
    header("Content-Transfer-Encoding: binary");
    header("Content-Length: $filesize");
    header("Cache-Control: cache, must-revalidate");
    header("Pragma: no-cache");

    ob_clean();
    flush();
    //readfile($filepath); //Read and stream the file
    ///*
    $fp = fopen($filepath, "rb"); //rb 읽기전용 바이러니 타입
    if(!fpassthru($fp)) {
        fclose($fp);
    }
    //*/
}
?>


위 다운로드 코드에 약간 문제가 있는지 다운로드가 제대로 되지 않는 폰이 있어서 코드를 다시 수정했다.

아래 코드는 정상적으로 잘 다운로드 된다. 여러 폰에서 테스트를 했다. (update 2019.6.18)

<?php
if(!isset($_SERVER['HTTP_REFERER'])) {
    echo 'direct access denied!';
    exit;
}

require_once "deviceChk.php"; // 접속 Device 체크
if($mtype==2){ // Android 폰 이면
    require_once 'config/config.php';
    $filepath = './files/'.$hostAbb.'.apk';
    $filesize = filesize($filepath);
    $path_parts = pathinfo($filepath);
    $filename = $path_parts['basename'];
    $extension = $path_parts['extension'];

   header('Content-Description: File Transfer');
   header('Content-Type: application/octet-stream');
   header('Content-Disposition: attachment; filename="' . $filename . '"');
   header("Content-Transfer-Encoding: Binary");
   header('Expires: 0');
   header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
   header('Pragma: public');
   header("Content-length: ".filesize($filepath));
   ob_clean();
   flush();
   readfile($filepath);
}
?>


블로그 이미지

Link2Me

,
728x90

MySQL DB 데이터를 csv 파일 형태로 저장하는 예제코드다.


<?php
$db['host'] = "localhost";
$db['name'] = "db명";
$db['user'] = "사용자id";
$db['pass'] = "비밀번호";
$db['port'] = "3306";
?>

<?php
include_once 'dbinfo.php';
$db = isConnectDb($db);

function isConnectDb($db)
{
    $conn = mysqli_connect($db['host'],$db['user'],$db['pass'],$db['name'],$db['port']);
    mysqli_set_charset($conn, "utf8"); 
    if (mysqli_connect_errno()) {
        echo "Failed to connect to MySQL: " . mysqli_connect_error();
        exit;
    } else {
        return $conn;
    }
}
?>

 <?php
$file_name = "cate_backup.xls";
header( "Content-type: application/vnd.ms-excel; charset=utf-8");
header( "Cache-Control: must-revalidate, post-check=0,pre-check=0" );
header( "Content-Disposition: attachment; filename=$file_name" );
header( "Content-Description: PHP4 Generated Data" );
//header() 함수를 쓰기전에 어떠한 출력도 있어선 안된다

include_once 'dbconect.php'; // DB 연동

$tblName = category;    // 테이블명
$sql ="SELECT uid, classname, relateduid FROM $tblName ORDER BY uid DESC";
// DESC 내림차순 정렬, ASC 오름차순 정렬
$result = mysqli_query($db,$sql);

// 테이블 상단 만들기
$EXCEL_STR = "
<table border='1'>
<tr>
<td align=center BGCOLOR='#9DEEE1'>번호</td>
<td align=center BGCOLOR='#9DEEE1'>구분자</td>
<td align=center BGCOLOR='#9DEEE1'>연관번호</td>
</tr>";

while ($row = mysqli_fetch_array($result) ){
    $EXCEL_STR .= "
    <tr>
    <td align=center>".$row['uid']."</td>
    <td align=center>".$row['classname']."</td>
    <td align=center>".$row['relateduid']."</td>
    </tr>
    ";
}

$EXCEL_STR .= "</table>";
echo $EXCEL_STR;
exit;
?>


블로그 이미지

Link2Me

,
728x90

csv 파일을 PHP를 이용하여 MySQL 에 업로드하는 예제코드다.

실전에서 활용하는 편리한 코드다.


<?php
error_reporting(0); // 경고 출력 방지, 주석처리해서 경고, 에러메시지 나오도록 하자.
require_once 'dbconnect.php';

date_default_timezone_set('Asia/Seoul');

// Edit upload location here
$tmpname    = $_FILES['file']['tmp_name'];
$realname    = $_FILES['file']['name'];

$fileExt    = getExt($realname);
$destination_path='uploads/';
$readFile = $destination_path . 'contactsdata.csv';

$errorFilename ="errorFile.txt";
$errorFile = $destination_path . $errorFilename;

$TABLENAME ='contacts'; // 테이블명

if (is_uploaded_file($tmpname)) {
    if (!strstr('[csv]',$fileExt)) {
        echo '<script type="text/javascript">alert("csv 파일만 등록할 수 있습니다.");</script>';
        exit;
    }
    move_uploaded_file($tmpname,$readFile);
    @chmod($readFile,0606);
}

/////////////////////////////////////////////////////////////////////////////////
$file_read = fopen($readFile,"r");
if(!$file_read){
    echo '<script type="text/javascript">alert("파일을 찾을 수가 없습니다!");</script>';
    echo "-2";
    exit;
}

// 파일 인코딩 모드 검사
$current_encoding = detectFileEncoding($readFile);
$total_line = 0;
$newcount = 0;
$upcount=0;
$ok = 0;

while($line = fgetcsv($file_read,1000, ";")) { // 구분자는 ; 로 지정
    // 파일 인코딩 모드 검사
    if($current_encoding != 'utf-8') {
        $line00 = iconv('euc-kr','utf-8',trim($line[0])); // 구분1(cat1)
        $line01 = iconv('euc-kr','utf-8',trim($line[1])); // 구분2(cat2)
        $line02 = iconv('euc-kr','utf-8',trim($line[3])); // officeNO
        $line03 = iconv('euc-kr','utf-8',trim($line[4])); // mobileNO
    } else {
        $line00 = trim($line[0]); // 구분1(cat1)
        $line01 = trim($line[1]); // 구분2(cat2)
        $line02 = trim($line[3]); // officeNO
        $line03 = trim($line[4]); // mobileNO
    }

    $cat1NM = $line00;
    $cat2NM = $line01;
    $officeNO = isset($line02) ? TelNumSplitRemove($line02) : '';
    $mobileNO = isset($line03) ? TelNumSplitRemove($line03) : '';

    $total_line++;
    if(strlen($mobileNO)<1) continue;

    // 구분1 코드 구하기
    $CA1= getDbData('category','name="'.$cat1NM.'" and parent_id=0','id');
    $cat1 = $CA1['id'];

    // 구분2 코드 구하기
    if(strlen($cat2NM)>0){
        $CA2= getDbData('category','parent_id="'.$cat1.'" and name="'.$cat2NM.'"','id');
        $cat2 = $CA2['id'];
    } else {
        $cat2 =0;
        continue; // 상황에 따라 체크 필요한 코드
    }

    $d_regis = date('Ymd');

    // 중복 등록 여부 검사
    $cnt = DataExistedChk($cat1,$cat2);
    if($cnt == "0"){
        $d_regis = date('Ymd');
        $QKEY = "cat1,cat2,officeNO,mobileNO";
        $QVAL = "'$cat1','$cat2','$officeNO','$mobileNO'";
        $rs = getDbInsert('contacts',$QKEY,$QVAL);
        $newcount++;
    } else {
        $QSET="officeNO='".$officeNO."',";
        $QSET.="mobileNO='".$mobileNO."'";
        $QVAL="cat1='".$cat1."' and cat2='".$cat2."' ";

        getDbUpdate('contacts',$QSET,$QVAL);
        $upcount++;
    }

    $ok ++;
    if (($ok % 500) == '0') {
        echo(" $ok 건 저장");
        flush();
        sleep(2); //500개 저장할때마다 2초씩 쉰다.
    }
} // while 문 종료
fclose($file_read);
unlink($readFile);  // 업로드 완료후에 파일 삭제 처리

$msg = '전체'.number_format($total_line).'건中 신규'.number_format($newcount).'건, 갱신'.number_format($upcount).'건 등록완료';
echo "<script type=\"text/javascript\">alert('$msg');</script>";

function getExt($filename){
    $ext = substr(strrchr($filename,"."),1);
    $ext = strtolower($ext);
    return $ext;
}

function detectFileEncoding($filepath) {
    // 리눅스 기본 기능을 활용한 파일 인코딩 검사
    $output = array();
    exec('file -i ' . $filepath, $output);
    if (isset($output[0])){
        $ex = explode('charset=', $output[0]);
        return isset($ex[1]) ? $ex[1] : null;
    }
    return null;
}

// ID Exist Check
function DataExistedChk($cat1,$cat2){
    global $db;
    $sql = "select count(*) from contacts where cat1='".$cat1."' and cat2='".$cat2."'";
    $result = mysqli_query($db,$sql);
    if($row = mysqli_fetch_row($result)){
        return $row[0];
    } else {
        return "0";
    }
}

//DB삽입
function getDbInsert($table,$key,$val){
    global $db;
    $sql ="insert into ".$table." (".$key.")values(".$val.")";
    if(mysqli_query($db,$sql)){
        return 1;
    } else {
        return 0;
    }
}

//DB업데이트
function getDbUpdate($table,$set,$where){
    global $db;
    mysqli_query($db,'set names utf8');
    mysqli_query($db,'set sql_mode=\'\'');
    $sql ="update ".$table." set ".$set.($where?' where '.getSqlFilter($where):'');
    if(mysqli_query($db,$sql)){
        return 1;
    } else {
        return 0;
    }
}

//SQL필터링
function getSqlFilter($sql)    {
    return $sql;
}


function TelNumSplitRemove($tel){
    return preg_replace("/[^0-9]/", "", $tel);    // 숫자 이외 제거
}
?>


블로그 이미지

Link2Me

,
728x90

PHP 로 jQuery 와 AJAX를 이용해서 파일을 업로드하는데 한참 삽질을 하고 적어둔다.

어쩌다 필요해서 하려고 하면 생각도 안나고 다시 제자리 걸음을 반복하는 초보자의 길을 언제나 벗어나려나 ㅠㅠ


MDB(Meterial Design Bootstrap) 기반 템플릿을 활용하여 코딩을 하느라고 class 가 이상것이 보이는 것이니 혹시라도 이 게시글을 읽으시는 분은 그냥 그런게 있나보다 하고 참조만 하시라.


파일 전송 Form 파일

<form id="uploadphoto" action="MemberPhotoUpload.php" method="post" enctype="multipart/form-data">
    <div class="card border-light mb-3" style="max-width: 30rem;">
      <div class="card-body text-dark">
        <h5 class="card-title">Image File Upload</h5>
        <input type="file" id="file" name="file" multiple />
        <input type="submit" value="Upload Photo" class="btnSubmit" />
      </div>
    </div>
</form> 

<table class='table table-responsive-sm' id='photoIDX' uid='<?php echo $idx;?>'>
    <tr><td colspan='5'>★★사진 등록시 [등록하기] , 사진 수정시 [사진을 클릭]하세요.</td></tr>
    <tr>
        <td rowspan='3'>
        <?php
            if(file_exists($imgpath)){
                echo "<img src='MemberPhotoView.php?idx=$idx&uid=$uid' width=115 height=140>";
            } else {
                echo "사진없음<br><span class='btn-floating peach-gradient photoBtn'><i class='fas fa-image'></i>등록하기</span>";
            }
        ?>
        </td>
        <th>아이디</th>
        <td><?php echo $row['userID'];?></td>
        <th>사무실번호</th>
        <td style='text-align:left;height:15px;'><?php echo $row['telNO'];?></td>
    </tr>
    <tr>
        <th>성명</th>
        <td><?php echo $row['userNM'];?></td>
        <th>휴대폰번호</th>
        <td style='text-align:left;height:15px;'><?php echo $mobileNO;?></td>
    </tr>
    <tr>
        <th>직위</th>
        <td><?php echo $chargeArr[$row['codeID']];?></td>
        <th>주업무</th>
        <td style='text-align:left;height:15px;'><?php echo $row['workrole'];?></td>
    </tr>
    <tr>
        <th>E-Mail</th>
        <td colspan='4' style='text-align:left;height:15px;'><?php echo $row['email'];?></td>
    </tr>
</table>


Script 파일

<script>

 $('.photoBtn').click(function(){
    var $obj=$(this);
    var idx=$(this).closest('#photoIDX').attr('uid');

    $('#dialog').load('MemberPhotoForm.php?idx='+idx, function() {
        $(this).dialog({
            autoOpen : true,
            height : 'auto',
            width : 'auto',
            position: { my: "center", at: "center", of: window },
            title : '사진 업로드',
            buttons : {
                "닫기" : function() {
                    $(this).dialog("close");
                }
            }
        });
        PhotoUploadChk(idx);
    });

});

function PhotoUploadChk(idx){
    $('form#uploadphoto').submit(function(e){
        e.preventDefault();
        var formData = new FormData();
        var files = $('#file')[0].files[0];
        formData.append('file',files);
        formData.append('uid',idx);

        formData.append('osType',$('select[name=osType]').val());

        var upfiles_cnt = $("input:file", this)[0].files.length;
        if(upfiles_cnt == 0){
            alert('선택된 파일이 없습니다.');
            return false;
        }

        $.ajax({
            url: 'MemberPhotoUpload.php',
            data: formData,
            cache: false,
            contentType: false,
            processData: false,
            type: 'post',
            success: function (msg) {
                if(msg == 1){
                    MemberView(idx);
                } else if(msg == 0){
                    alert('form 데이터 오류인지 확인하세요.');
                } else {
                    alert('파일이 업로드되지 못했습니다.');
                }
            }
        });

    });

}
</script>


PHP 파일 업로드 관련 파일

<?php
if(isset($_POST['uid']) && $_POST['uid']>0){
    $idx=$_POST['uid'];

    $tmpname    = $_FILES['file']['tmp_name'];
    $realname    = $_FILES['file']['name'];
    $fileExt    = getExt($realname);

    $file_path='./photos/'.$idx.'.jpg';

    if (is_uploaded_file($tmpname)) {
        if (!strstr('[jpg]',$fileExt)) {
            echo "-1";
            exit;
        }
        move_uploaded_file($tmpname,$file_path);
        @chmod($file_path,0606);
        echo "1";
    }
} else {
    echo "0";
}

function getExt($filename){
    $ext = substr(strrchr($filename,"."),1);
    $ext = strtolower($ext);
    return $ext;
}
?>


파일 사이즈 검사하여 파일 사이즈를 줄이는 코드는 포함되지 않았다.


$("#uploadbutton").click(function(){
    var form = $('form')[0]; // 폼객체를 불러와서
    var formData = new FormData(form); // FormData parameter 에 담아줌
    $.ajax({
        url: 'fileupload',
        processData: false,
        contentType: false,
        data: formData,
        type: 'POST',
        success: function(result){
            alert("업로드 성공!!");
        }
    });
});

블로그 이미지

Link2Me

,
728x90

폴더안에 있는 파일들의 파일명을 배열(array)로 저장하고 출력해보자.

basename($_FILES['b_file']['name']); // basename() 메소드는 경로를 제외하고 파일명만 추출

pathinfo($filename, PATHINFO_FILENAME); //확장자를 제외한 파일명
pathinfo($filename, PATHINFO_EXTENSION); // 파일 확장자 구하기


<?php
$dir ='./photos'; // 폴더명 지정

$fileList = getCurrentFileList($dir);
echo count($fileList).'개 검색됨<br />';
foreach($fileList as $f){
    echo $f.'<br />';
}

function getCurrentFileList($dir){
    $valid_formats = array("jpg","png");
    $handle = opendir($dir); // 디렉토리의 핸들을 얻어옴
    // 지정한 디렉토리에 있는 디렉토리와 파일들의 이름을 배열로 읽어들임
    $R = array(); // 결과 담을 변수 생성
    while ($filename = readdir($handle)) {
        if($filename == '.' || $filename == '..') continue;
        $filepath = $dir.'/'.$filename;
        if(is_file($filepath)){ // 파일인 경우에만
            $getExt = pathinfo($filename, PATHINFO_EXTENSION); // 파일 확장자 구하기
            if(in_array($getExt, $valid_formats)){
                array_push($R,basename($filename,'.jpg')); // 파일이름만 선택하여 배열에 넣는다.
            }
        }
    }
    closedir($handle);
    sort($R); // 가나다순으로 정렬하기 위해
    return $R;
}
?>


블로그 이미지

Link2Me

,
728x90

아래 코드는 MySQL DB 테이블에 있는 자료를 CSV 파일로 저장하는 예제다.

while 문을 사용하면 4만개 정도의 데이터도 매우 빠르게 저장된다.

for문, foreach문을 사용하면 매우 느리다.

저장된 데이터를 엑셀에서 읽었을 때 깨져보이면 charset=utf-8 를 charset=euc-kr 로 저장하면 될 것이다.

자료 저장 형태가 CSV 라는 것은 EditPlus 와 같은 툴로 읽어도 내용이 보인다는 거다.

그러므로 엑셀에서 수정하고 저장할 때 반드시 다른 이름으로 저장을 선택하여 저장형식을 엑셀 형식으로 저장해야 한다. 바로 저장을 하면 파일 구조가 web 파일 형태로 저장되어 이상하게 보일 것이다.


<?php
if(!isset($_SESSION)) {
    session_start();
}

$file_name = "Park.xls";
header( "Content-type: application/vnd.ms-excel; charset=euc-kr");
header( "Cache-Control: must-revalidate, post-check=0,pre-check=0" );
header( "Content-Disposition: attachment; filename=".$file_name);
header( "Content-Description: PHP4 Generated Data" );


include_once '../dbinfo.php';
include_once '../dbconnect.php'; // DB 접속

$tblName = data;    // 테이블명
$result = mysql_query("SELECT uid, (select classname from category where uid=data.category1) as cate1,(select classname from category where uid=data.category2) as cate2,content FROM $tblName where sysrole = 0 ORDER BY uid DESC", $dbconn);
// DESC 내림차순 정렬, ASC 오름차순 정렬

// 테이블 상단 만들기
$EXCEL_STR = "
<table border='1'>
<tr>
<td ALIGN=CENTER BGCOLOR='#9DEEE1'>UID</td>
<td ALIGN=CENTER BGCOLOR='#9DEEE1'>구분1</td>
<td ALIGN=CENTER BGCOLOR='#9DEEE1'>구분2</td>
<td ALIGN=CENTER BGCOLOR='#9DEEE1'>내용</td>
</tr>";

while ($row = mysql_fetch_array($result) ){
    $EXCEL_STR .= "
    <tr>
    <td ALIGN=CENTER>".$row['uid']."</td>   
    <td ALIGN=CENTER>".$row['cate1']."</td>
    <td ALIGN=CENTER>".$row['cate2']."</td>
    <td>".stripslashes($row['content'])."</td> 
    </tr>
    ";
}

$EXCEL_STR .= "</table>";
echo $EXCEL_STR;
mysql_free_result ($result);

exit;

?>

블로그 이미지

Link2Me

,
728x90

PHP 폴더내 파일 개수를 구하는 함수를 만들어보자.


검색해보니

function dirs_chk($dir){
 $dirs=count(scandir($dir)); 
 echo $dirs;
}
$dir = 'uploads/';
echo dirs_chk($dir);

로 하면 파일 개수를 구할 수 있다고 해서 테스트를 해보니 이건 sub 폴더까지 검색하는데 문제는 . 과 .. 까지 카운트를 한다. 그래서 원하는 개수를 정확하게 구할 수가 없다.


http://www.webmadang.net/develop/develop.do?action=read&boardid=1003&page=1&seq=65

에 있는 걸로 테스트를 했더니 제대로 나오는데 경고 메시지가 출력된다.


원하는 사항은 특정 폴더내에서 특정 확장자를 가진 파일의 개수를 반환하고자 한다.

그래서 경고메시지 나오는 부분을 수정했고 특정 확장자만 검사하도록 코드를 추가했다.


<?php
$doc_root = $_SERVER["DOCUMENT_ROOT"]; // Web서버 root directory
$dir=$doc_root.'/fileupload/uploads/';
$dir_count = 0;
$file_count = 0;
$valid_formats = array("jpg", "png", "gif");

// 디렉토리에 있는 파일과 디렉토리의 갯수 구하기
$result = opendir($dir); //opendir 함수를 이용해서 디렉토리의 핸들을 얻어옴
// readdir함수로 지정 디렉토리에 있는 디렉토리와 파일들의 이름을 배열로 읽어들임
while($file = readdir($result)) {
    if($file === "."|| $file === "..") continue; // file명이 ".", ".." 이면 무시함
    $getExt = pathinfo($file, PATHINFO_EXTENSION); // 파일의 확장자를 구함

    if(empty($getExt)){
        $dir_count++; // 파일에 확장자가 없으면 디렉토리로 판단하여 dir_count를 증가시킴
    } else {
        if(in_array($getExt, $valid_formats)){
            $file_count++; // 검사조건에 맞는 파일이 있으면 카운트
        }
    }
}

echo"디렉토리 갯수 : ".$dir_count."<br>";
echo"파일의 갯수 : ".$file_count;
?>


이제 다른 곳에서 사용하기 위해서 함수화를 해보자.


// 지정 디렉토리내의 지정 파일 개수 구하기

function getFilesCount_CurDir($dir){
    $dir_count = 0;
    $file_count = 0;
    $valid_formats = array("jpg", "png", "gif"); // 그림 확장자 지정
   
    // 디렉토리에 있는 파일과 디렉토리의 갯수 구하기
    $result = opendir($dir); //opendir 함수를 이용해서 디렉토리의 핸들을 얻어옴
    // readdir함수를 이용해서 디렉토리에 있는 디렉토리와 파일들의 이름을 배열로 읽어들임
    while($file = readdir($result)) {
        if($file === "."|| $file === "..") continue; // file명이 ".", ".." 이면 무시함
        $getExt = pathinfo($file, PATHINFO_EXTENSION); // 파일의 확장자를 구함

        if(!empty($getExt)){
            if(in_array($getExt, $valid_formats)){
                $file_count++; // 검사조건에 맞는 파일이 있으면 카운트
            }
        }
    }
    return $file_count;
}


블로그 이미지

Link2Me

,
728x90

jQuery ajax 를 사용하지 않는 jQuery 를 http://link2me.tistory.com/1142 에서 다루었다.


=== fileupload.js ===

$(document).ready(function() {
    $('#form').submit(function(){
        var
upfiles_cnt = $("input:file", this)[0].files.length;
        if(
upfiles_cnt == 0){
            alert('선택한 파일이 없습니다');
            return false; // form을 전송시키지 않고 반환
        }
    });
});

ajax 방식을 사용한 jQuery 를 구현해보자.

파일 업로드 현황을 progress bar 로 구현하려고 구글링을 하면서 개념 이해 및 테스트 중이다.

ajax 로 파일 전송시 현재 업로드한 파일 숫자가 0 인지 체크 로직을 추가하여 처리하도록 구현했다.

구글링을 해서 이 방법 저 방법 테스트를 해보니 formData 부분에서 에러가 발생하더라.


=== fileupload.js ===

$(document).ready(function() {

    $('#form').submit(function(e){
        //disable the default form submission
        e.preventDefault();

        //grab all form data <== 필요에 따라 코드 수정해서 사용해야 함.
        var form = $('form')[0];
        var formData = new FormData(form);


        var upfiles_cnt = $("input:file", this)[0].files.length;
        if(upfiles_cnt == 0){
            alert('선택한 파일이 없습니다');
            return false; // form을 전송시키지 않고 반환
        }


        $.ajax({
            url: "fileupload.php",
            data: formData,
            cache: false,
            contentType: false,
            processData: false,
            type: 'POST',
            dataType: "json",
            success: function (data) {
                $('.status').html(data + ' Files uploaded!').fadeIn();
            },
            error: function(){
                alert("error in ajax form submission");
            }
        });

        return false;
    });

});



Upload Progress bar 검색해보면 대부분 아래 코드와 유사한 것이 검색된다.

그런데 이코드를 수정해서 Upload 파일 갯수가 0이면 진행이 안되게 하려고 테스트 하니 잘 안된다.


=== fileupload.js ===
$(document).ready(function() {

    $('form').ajaxForm({
        /* set data type json */
        dataType:  'json',

        /* reset before submitting */
        beforeSend: function() {
            status.fadeOut();
            bar.width('0%');
            percent.html('0%');
        },

        /* progress bar call back*/
        uploadProgress: function(event, position, total, percentComplete) {
            var pVel = percentComplete + '%';
            bar.width(pVel);
            percent.html(pVel);
        },

        /* complete call back */
        complete: function(data) {
            status.html(data.responseJSON.count + ' Files uploaded!').fadeIn();
        }
    });
});



http://phppot.com/jquery/jquery-progress-bar-for-php-ajax-file-upload/ 사이트를 발견하고 이걸 참조하여 구현했더니 원하는 결과가 나온다.


아래 코드는 에러 없이 정상 동작한다.

//grab all form data
var form = $('form')[0];
var formData = new FormData(form);


그런데 파일 전송시

<input type="hidden" name="uid" value="">

<input type="file" id="file" name="file" multiple />

와 같이 이미지 파일 외에 uid 값까지 같이 전송되도록 하려니까 잘 전송이 안된다.


var formData = new FormData();
var files = $('#file')[0].files[0];
formData.append('file',files);
formData.append('uid',idx);

와 같이 해주고 나서 정상적으로 전송이 된다.


=== fileupload.js ===
$(document).ready(function() {

    $('#form').submit(function(e){
        //disable the actual submit of the form.
        e.preventDefault();
       
        //grab all form data
        var form = $('form')[0];
        var formData = new FormData(form);

        var upfiles_cnt = $("input:file", this)[0].files.length;
        if(upfiles_cnt == 0){
            alert('선택한 파일이 없습니다');
            return false; // form을 전송시키지 않고 반환
        }

        $(this).ajaxSubmit({
            // set data type json
            dataType:  'json',

            // reset before submitting
            beforeSend: function() {
                status.fadeOut();
                bar.width('0%');
                percent.html('0%');
            },

            // progress bar call back
            uploadProgress: function(event, position, total, percentComplete) {
                var pVel = percentComplete + '%';
                bar.width(pVel);
                percent.html(pVel);
            },

            complete: function(data) {
                status.html(data.responseJSON.count + ' Files uploaded!').fadeIn();
            },
            resetForm: true
        });
        return false;
    });
});



progress bar 가 나오는 ajax 방법으로 구현해보려고 시도하면서 검색/테스트 많이 했다.

나와 같은 jQuery 초보자를 위해서 고생하지 말라고 테스트한 파일을 첨부합니다.


fileupload_ajax.zip



도움되셨다면 공감 눌러주시거나 00 00 한번 해주시길

블로그 이미지

Link2Me

,
728x90

파일 업로드 관련으로 Javascript 와 jQuery 를 검색하고 필요한 것을 추가/수정해서 작성했다.

파일 중복 체크를 안하려고 파일명을 rename 처리했다.

$rename = md5(uniqid($tmpname)) .round(microtime(true)).'.'.$fileExt;


파일 테스트 환경 : Windows10 AutoSet9, Linux CentOS 6.5


테스트에 사용한 첨부파일

fileupload-01.zip



=== fileform.php ===

<!DOCTYPE html>
<html>
<head>
<title>Multiple File Upload with PHP</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="css/pure-min.css">
<link rel="stylesheet" type="text/css" href="css/fileupload.css">
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<!-- javascript dependencies -->
<script type="text/javascript" src="js/jquery.form.min.js"></script>
<!-- main script -->
<script type="text/javascript" src="js/fileupload.js"></script>
<script type="text/javascript">
    function viewFileList() {
        var input = document.getElementById("files");
        var ul = document.getElementById("fileList");
        while (ul.hasChildNodes()) {
            ul.removeChild(ul.firstChild);
        }
        for (var i = 0; i < input.files.length; i++) {
            var li = document.createElement("li");
            li.innerHTML = input.files[i].name;
            ul.appendChild(li);
        }
        if(!ul.hasChildNodes()) {
            var li = document.createElement("li");
            li.innerHTML = 'No Files Selected';
            ul.appendChild(li);
        }
    }
</script>
</head>
<body>
<div class="container">
    <div class="status"></div>
    <form id="form" action="fileupload.php" method="post" enctype="multipart/form-data" >
        <input type="file" id="files" name="files[]" multiple="multiple" onChange="viewFileList();" />
        <input type="submit" value="Upload" class="pure-button" />
    </form>
    <ul id="fileList"><li>No Files Selected</li></ul>
    <div class="progress">
        <div class="bar"></div>
        <div class="percent">0%</div>
    </div>

</div><!-- end .container -->

</body>
</html>


=== fileupload.js ===

$(document).ready(function() {
    $('#form').submit(function(){
        var numFiles = $("input:file", this)[0].files.length;
        if(numFiles == 0){
            alert('선택된 파일이 없습니다');
            return false; // form을 전송시키지 않고 반환
        }
    });
});


=== fileupload.php ===

<?php
// Edit upload location here
$valid_formats = array("jpg", "png", "gif", "bmp");
$max_file_size = 1024*100; //100 kb
$upload_path='uploads/';
$count = 0;
if(isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST"){
    foreach ($_FILES['files']['name'] as $i => $name) {
        if ($_FILES['files']['error'][$i] == 4) { // 파일이 전송되지 않았습니다
            continue;
        }
        if ($_FILES['files']['error'][$i] == 0) { // 오류 없이 파일 업로드 성공
            if ($_FILES['files']['size'][$i] > $max_file_size) {
                $message[] = "$name is too large!.";
                continue;
            }elseif( ! in_array(pathinfo($name, PATHINFO_EXTENSION), $valid_formats) ){
                $message[] = "$name 은 허용된 파일 포멧이 아닙니다";
                continue;
            }else{ // 에러가 없으면
                $tmpname = $_FILES['files']['tmp_name'][$i];
                $realname = $_FILES['files']['name'][$i];
                $filesize = $_FILES['files']['size'][$i];
                $fileExt = getExt($realname);
                $rename = md5(uniqid($tmpname)) .round(microtime(true)).'.'.$fileExt;
                $uploadFile = $upload_path . $rename;
                if(move_uploaded_file($tmpname, $uploadFile)){
                    @chmod($readFile,0606);

                    // DB 테이블에 저장하는 루틴은 여기에 추가하면 된다.

                    $count++; // 업로드 성공한 파일 숫자
                }
            }
        }
    }
}

echo $count;
?>

<script type="text/javascript">
var count ='<?php echo $count;?>';
alert('업로드 성공 파일수 : ' + count );
setTimeout(function() {
    window.location.replace("fileform.php");
}, 1000);
</script>

<?php
// 확장자 추출 함수
function getExt($filename){
    $ext = substr(strrchr($filename,"."),1);
    $ext = strtolower($ext);
    return $ext;
}
?>



파일 업로드 / 다운로드 취약점
- 업로드 기능에서 파일 사이즈의 제한을 주지 않을 경우
- 파일 타입의 체크가 없는 경우
- 파일이 업로드 되는 경로가 외부에서 직접적으로 접근 가능하거나 실행 권한을 가지게 되는 경우


파일 업로드할 때 @chmod($readFile,0606); 를 하는 이유를 좀 더 알고자 한다면

http://www.macinstruct.com/node/415 에 나오는 그림을 보면 도움된다.

업로드라 함은 파일을 서버에 쓰는(write)하는 것이다.

그러므로 파일을 read(4) + write(2) 권한만 부여하면 된다. 파일을 실행할 수 있게 하면 보안상에 문제가 될 수도 있다. 그래서 업로드한 파일을 읽기와 쓰기 권한만 부여했다.


보안을 위해서 몇가지 더 권고하는 걸 적어둔다.

- 업로드한 파일을 외부에서 접근할 수 없는 경로에 저장한다.

  즉 Web 서버 URL 밖에다가 저장하도록 하는 것이 좋다.

- 업로드한 파일에 대한 웹서버의 실행권한을 제거하고 저장한다.

- 업로드한 파일의 저장 경로와 파일명을 외부에서 알 수 없도록 한다.

  실제 저장되는 파일명은 난수를 이용해 유추 불가능하도록 생성하여 외부로부터 직접적인 접근이 불가능하게 구현한다.

  업로드한 파일을 위한 전용 디렉토리를 생성하여 실행권한을 제거한다.


참고

파일 업로드에 대한 개념 설명이 잘된 URL

http://blog.habonyphp.com/entry/php-POST-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C#.WHWm81z3TFA


블로그 이미지

Link2Me

,
728x90

파일을 업로드하는 코딩시 고려할 사항이다.


파일을 업로드시에 공격이 성공하면 바로 서버가 해킹되는 것이기 때문에 가장 리스크가 큰 취약점이다.

보안(Security)을 고려하고 실행파일이 업로드되지 않도록 해야 한다.

먼저, 파일 업로드 기능이 있는 페이지를 전부 조사해서 WebShell 같은 악의적인 파일이 업로드될 수 있는지 체크해야 한다.


1. 파일 업로드시 확장자 검사 루틴

    - 기본적으로는 Apache 환경설정에서 mine type 필터링을 설정한다.

      Apache 환경설정 http://link2me.tistory.com/426  http://link2me.tistory.com/991 참조

    <IfModule mime_module>
        TypesConfig conf/mime.types
        AddType application/x-compress .Z
        AddType application/x-gzip .gz .tgz
        AddType application/x-httpd-php .php .html
        AddType application/x-httpd-php-source .phps
    </IfModule>


   - 하지만 공격자가 Proxy-Server 등을 통해 우회할 수 있으므로 확장자 필터링을 적용한다.

     업로드가 허용된 확장자만 업로드가 가능하도록 서버 필터링을 하여야 한다.

 

2. 파일명은 치환(난수화)해서 저장한다.
    그리고 파일 접근권한을 읽기 전용모드로 등록한다. (실행권한 부여 금지)


3. 등록시 변경 파일명을 DB에 저장한다.

    - 게시판에 첨부되는 파일명인 경우, 변경 파일명을 DB 테이블에 기록하여 찾을 수 있도록 한다.


4. 가능하면 파일 업로드 장소를 물리적으로 분리한다.

    물리적으로 분리하지 않은 경우라면 해당 디렉토리가 어디인지 알수 없게 다른 곳으로 지정한다.


파일 업로드시 제한 용량은 php.ini 파일에 설정되어 있다.

업로드 용량을 많이 설정하려면 php.ini 파일을 수정하고 Apache 를 restart 해야 한다.

; PHP 가 받아들이는 POST data 최대 크기
; default 8M 로 되어 있음, upload_max_filesize 보다 크게 설정해야 함
post_max_size = 20M
memory_limit = 128M
upload_max_filesize = 19M


// 테이블 구조 예시

CREATE TABLE IF NOT EXISTS file_upload (
  uid int(11) NOT NULL AUTO_INCREMENT,
  folder varchar(10) NOT NULL DEFAULT '',
  name varchar(250) NOT NULL DEFAULT '',
  size int(11) NOT NULL DEFAULT '0',
  d_regis varchar(14) NOT NULL DEFAULT '',
  PRIMARY KEY (uid),
  KEY d_regis (d_regis)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;


//파일을 전송하는 PHP 소스 부분

파일명을 excel 로 사용했으면 받는 쪽에서도 excel 로 사용해야 한다.

보통은 userfile 이라고 많이 쓴다.

<form enctype="multipart/form-data" action="fileupload.php" method="POST">
 <input 
type="file" name="excel"  />

 <input type="submit" value="upload" />
</form>



// 파일을 전송받은 PHP 소스 부분

여러개의 확장자를 검사하려면 strstr('[csv]',$fileExt) 부분을 수정하면 된다.

strstr('[csv,php,html,htm,inc,do]',$fileExt) 와 같이 확장자 여러개를 나열해준다.


<?php
    // Edit upload location here
    $tmpname    = $_FILES['excel']['tmp_name'];
    $realname    = $_FILES['excel']['name'];
    $fileExt    = getExt($realname);  // 확장자 필터링을 위한 확장자 추출
    $destination_path='uploads/';
    $rndname = hash('sha256', $realname).date("Ymd").'.'.$fileExt;  // 파일명 hash 처리
    $readFile = $destination_path . $rndname;

    if (is_uploaded_file($tmpname)) {
        if (!strstr('[csv]',$fileExt)) {  // 확장자 필터링 검사
            echo '<script type="text/javascript">alert("csv 파일만 등록할 수 있습니다.");</script>';
            exit;
        }
        move_uploaded_file($tmpname,$readFile);
        @chmod($readFile,0404);  // 파일 권한을 읽기모드로 설정

    }

    function getExt($filename){
        $ext = substr(strrchr($filename,"."),1); // 뒤에서부터 콤마 위치로부터 가져오기
        $ext = strtolower($ext); // 소문자로 강제치환
        return $ext;
    }

    ?>



아래 코드는 업로드시 파일명을 치환하는 연습 코드이다.


<?php
//$realname = strtolower($_FILES['excel']['name']);
$realname = 'shell.asp;.jpg';
$fileExt = getExt($realname);
//$tmpname = md5($realname).date("Ymd").'.'.$fileExt;
$tmpname = hash('sha256', $realname).date("Ymd").'.'.$fileExt;

echo $tmpname;
echo '<br />';
echo strlen($tmpname);

function getExt($filename){
    $ext = substr(strrchr($filename,"."),1); // 뒤에서부터 콤마 위치로부터 가져오기
    $ext = strtolower($ext); // 소문자로 강제치환
    return $ext;
}

?>


파일을 2개 업로드하는 걸 고려한다면

<form enctype="multipart/form-data" action="fileupload.php" method="POST">

이미지 파일1 <input type="file" name="imagefile[]">

이미지 파일2 <input type="file" name="imagefile[]">

<input type="submit" value="upload" />

</form>


fileupload.php 에서 확인해 볼 사항

echo '<pre>', print_r($_FILES) ,"</pre>";

$_FILES['imagefile']['name'][0];

$_FILES['imagefile']['name'][1];

$_FILES['imagefile']['type'][0];

$_FILES['imagefile']['type'][1];

$_FILES['imagefile']['tmp_name'][0];

$_FILES['imagefile']['tmp_name'][1];

$_FILES['imagefile']['size'][0];

$_FILES['imagefile']['size'][1];

$_FILES['imagefile']['error'][0];

$_FILES['imagefile']['error'][1];


참조하면 도움되는 게시글

http://blog.habonyphp.com/entry/php-POST-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C#.V5RntaKzHpU


jQuery PHP 파일 업로드 게시글 : http://link2me.tistory.com/1142


Ajax PHP 파일 업로드 게시글 : http://link2me.tistory.com/1143

블로그 이미지

Link2Me

,
728x90

서버가 CentOS7 환경이라면 https://link2me.tistory.com/1842 를 참고해야 한다.


웹파일 형식으로 내보내기를 하면 속도가 짱 빠르기 때문에 사용하는데 문제가 없다.

<?php
if(!isset($_SESSION)) {
    session_start();
}

$file_name = "xxx_code.xls";
header( "Content-type: application/vnd.ms-excel; charset=utf-8");
header( "Cache-Control: must-revalidate, post-check=0,pre-check=0" );
header( "Content-Disposition: attachment; filename=$file_name" );
header( "Content-Description: PHP4 Generated Data" );


error_reporting(E_ALL ^ E_NOTICE);

include_once 'db.info.php';
include_once 'function/db.mysql.func.php';
$DB_CONNECT = isConnectDb($DB);


?>


윈도우10 환경하에서 인식이 제대로 안되는 현상이 생겨서 이번 기회에 엑셀 파일로 직접 저장하는 법을 찾아봤다.

엑셀로 저장하면 일단 속도가 많이 느리다.


https://github.com/PHPOffice/PHPExcel 에서 파일을 다운로드한다.

다운로드 한 파일을 압축을 풀어서 서버에 업로드한다.


아래 코드처럼 작성하면 된다.


<?php
if(!isset($_SESSION)) {
    session_start();
}
if(!empty($_SESSION['userID'])){
    echo "<script>window.top.location.replace('/index.php');</script>";
    exit;
}

$fname="xxx_code";  // 저장할 파일명
// 파일의 저장형식이 utf-8일 경우 한글파일 이름은 깨지므로 euc-kr로 변환해준다.
//$fname = iconv("UTF-8", "EUC-KR", "한글이름");

require_once "dbconnect.php";
require_once 'phpclass/PHPExcel.php';

$objPHPExcel = new PHPExcel();
$objPHPExcel->setActiveSheetIndex(0); //set first sheet as active

$objSheet = $objPHPExcel->getActiveSheet();
$objSheet->setTitle('코드');
$objSheet->getCell('A1')->setValue('코드');
$objSheet->getDefaultStyle('A1')->getFont()->setName('맑은 고딕');
$objSheet->mergeCells('A1:M1'); // 셀 병합
$objSheet->getStyle('A1')->getFont()->setSize(16); // 셀의 textsize

$objPHPExcel->getDefaultStyle()->getFont()->setSize(12); // 폰트 사이즈
$objSheet->SetCellValue('A2', "NO");
$objSheet->mergeCells('A2:A3'); // 셀 병합
$objSheet->SetCellValue('B2', "부서");
$objSheet->mergeCells('B2:E2');
$objSheet->SetCellValue('F2', "순서");
$objSheet->mergeCells('F2:I2');
$objSheet->SetCellValue('J2', "코드");
$objSheet->mergeCells('J2:M2');

$objSheet->SetCellValue('B3', "부서1");
$objSheet->SetCellValue('C3', "부서2");
$objSheet->SetCellValue('D3', "부서3");
$objSheet->SetCellValue('E3', "부서4");

$objSheet->SetCellValue('F3', "계위1");
$objSheet->SetCellValue('G3', "계위2");
$objSheet->SetCellValue('H3', "계위3");
$objSheet->SetCellValue('I3', "계위4");

$objSheet->SetCellValue('J3', "계위1");
$objSheet->SetCellValue('K3', "계위2");
$objSheet->SetCellValue('L3', "계위3");
$objSheet->SetCellValue('M3', "계위4");

cellColor('A2:M3', 'F28A8C'); // 헤더 배경색 지정

$i=4; // 값을 기록할 셀의 시작위치
$rowCount = 1; // 넘버링

$sql="select * from tablename where 조건";
$result=mysql_query($sql);
while($row=mysql_fetch_row($result)){


    $objSheet->SetCellValue('A'.$i, $rowCount);
    $objSheet->SetCellValue('B'.$i, $row[0]);
    $objSheet->SetCellValue('C'.$i, $row[1]);
    $objSheet->SetCellValue('D'.$i, $row[2]);
    $objSheet->SetCellValue('E'.$i, $row[3]);

    $objSheet->SetCellValue('F'.$i, $row[4]);
    $objSheet->SetCellValue('G'.$i, $row[5]);
    $objSheet->SetCellValue('H'.$i, $row[6]);
    $objSheet->SetCellValue('I'.$i, $row[7]);

    $objSheet->SetCellValue('J'.$i, $row[8]);
    $objSheet->SetCellValue('K'.$i, $row[9]);
    $objSheet->SetCellValue('L'.$i, $row[10]);
    $objSheet->SetCellValue('M'.$i, $row[11]);

    $i++;
    $rowCount++;
}

// 표 그리기
$i--;
$objSheet->getStyle('A2:M'.$i)->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);

// 헤더 칼럼 가운데 정렬
$objSheet->getStyle('A2:M'.$i)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);

// 셀 높이
$objSheet->getRowDimension(1)->setRowHeight(20);

// 칼럼 사이즈 자동 조정
$objSheet->getColumnDimension('A')->setAutoSize(true);
$objSheet->getColumnDimension('B')->setWidth(18);  // 칼럼 크기 직접 지정
$objSheet->getColumnDimension('C')->setWidth(18);
$objSheet->getColumnDimension('D')->setWidth(18);
$objSheet->getColumnDimension('E')->setWidth(18);

// 파일 PC로 다운로드
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename='.$fname.'.xlsx');
header('Cache-Control: max-age=0');

$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, "Excel2007");
$objWriter->save('php://output');
exit;

function SaveViaTempFile($objWriter){
    $filePath = '/tmp/' . rand(0, getrandmax()) . rand(0, getrandmax()) . ".tmp";
    $objWriter->save($filePath);
    readfile($filePath);
    unlink($filePath);
}

// 엑셀의 셀 배경색 지정
function cellColor($cells,$color){
    global $objSheet;

    $objSheet->getStyle($cells)->getFill()->applyFromArray(array(
        'type' => PHPExcel_Style_Fill::FILL_SOLID,
        'startcolor' => array(
             'rgb' => $color
        )
    ));
}

?>

블로그 이미지

Link2Me

,
728x90

PHP 에서 파일 인코딩을 검사하는 함수다.
구글신이 알려주길래 테스트 해봤더니 잘 되는거 같다.

다른 함수가 부정확할 수도 있다면서 나와 있길래 인코딩 검사를 해봤다.

C# 에서는 인코딩 검사하는 거 찾기 어렵던데 PHP에서는 쉽게 해결이 되는 거 같다.


function detectFileEncoding($filepath) {
    // 리눅스 기본 기능을 활용한 파일 인코딩 검사
    $output = array();
    exec('file -i ' . $filepath, $output);
    if (isset($output[0])){
        $ex = explode('charset=', $output[0]);
        return isset($ex[1]) ? $ex[1] : null;
    }
    return null;
}


블로그 이미지

Link2Me

,
728x90
fgets(파일, 읽을 최대크기(바이트)); // 지정된 길이 만큼 읽어오되 \n을 만나면 종료한다.

fgetcsv( 파일, 읽을 최대크기(바이트), '구분자' ); // 파일에서 읽은 내용을 구분자로 나누어 배열로 저장

fread(파일, 임의의 길이(바이트)) ; 개행문자(\n)까지 길이로 인식한다.

파일 전체를 다 읽어 들이고 싶은 경우는 fread($fp,filesize($fp));

while ( !feof($fp) ) { //처리할 내용 }  // feof() 함수를 이용하면 끝까지 읽는다


<?php
$datafile = "1234.txt";
if(!file_exists($datafile))
{
    echo '<p>'.$datafile.' 파일이 없습니다</p>';
    exit;
}
 
$fp = fopen($datafile"r");
if ($fp) {
    while (($line = fgets($fp4096)) !== false// 한줄씩 읽어서 파일이 끝날때까지 loop
    {
        $tmp_array = explode"_" ,$line);  // 구분자를 기준으로 분할한 후 배열로
 
        for($i=0 ; $i < count($tmp_array- 1$i++) {
            $sub_array = explode(":",$tmp_array[1]); // 두번째 배열을 다시 분할한 후 배열로
            echo $line." --> "."변수 : ".$tmp_array[0]."_".$sub_array[0]." , value : ".$sub_array[1] ."<br>";
        }
    }
 
    if (!feof($fp)) {
        echo "Error: unexpected fgets() fail\n";
    }
}
 
fclose($fp);
?>



블로그 이미지

Link2Me

,
728x90

서버에 업로드한 파일을 읽어서 파일의 내용을 분석하여 화면에 뿌리는 방법을 테스트 해보려고 작성해본 거다.

보통 엑셀 파일을 VBA 로 내보내기를 하면 인코딩 모드가 euc-kr 모드로 되어 있다.

그래서 서버에 설정된 인코딩모드가 UTF-8 이면 파일의 인코딩 모드를 변경해줘야 한다.

한줄씩 읽어서 한줄내의 구분을 ; 로 하는데, line[0], line[1] 이런 식으로 배열로 받아들인다.

보통 DB에서 가져오면 배열 형태로 바로 화면에 출력하는데, 때로는 가공을 한 다음에 화면에 뿌리거나 다시 DB에 저장해야 할 때가 있다.

이때 가져온 필드를 배열로 만드는 함수가 array_push 이다.


<?php
echo "파일 연습";
echo "<br />";

$file=fopen("data.csv","r");
if(!$file){
    echo("Failed to open the file");
    exit;
} else {
    echo "파일이 정상적으로 열렸습니다";
    echo "<br />";

}

while($line = fgetcsv($file,1000, ";")) { // 구분자는 ; 로 지정, 한줄씩 라인끝까지 읽어라.

$line0 = iconv('euc-kr','utf-8',$line[0]); // euc_kr 자료를 utf-8 로 인코딩 모드 변환
$line1 = iconv('euc-kr','utf-8',$line[1]);
$line2 = iconv('euc-kr','utf-8',$line[2]);
$line3 = iconv('euc-kr','utf-8',$line[3]);
$line4 = iconv('euc-kr','utf-8',$line[4]);
$line5 = iconv('euc-kr','utf-8',$line[5]);
$line6 = iconv('euc-kr','utf-8',$line[6]);

$subject = addslashes(trim($line0));
$content = addslashes(trim($line1));
$category = trim($line2);
$line[3] = addslashes(trim($line3));
$line[4] = addslashes(trim($line4));
$line[5] = addslashes(trim($line5));
$line[6] = addslashes(trim($line6));

echo "제목 : ".$subject;
echo "<br />";
echo "내용 : ".$content;
echo "<br />";

$contentstr = explode("/", $content);
echo count($contentstr);
echo "<br />";
$content    = count($contentstr) ? trim($contentstr[0]) : $content;
$content1    = $contentstr[1] ? trim($contentstr[1]) : '';
$content2    = $contentstr[2] ? trim($contentstr[2]) : '';

echo "content = ".$content;
echo "<br />";
echo "content1 = ".$content1;
echo "<br />";
echo "content2 = ".$content2;
echo "<br />";

$search = array();
for( $i = 0; $i < 4; $i++ ) {
    array_push($search, $line[$i+3]);
    if (!$search[$i]) break;    // 값이 없으면 for 문을 빠져나가라
    echo $i." = ".$search[$i];
    echo "<br />";
// for 문 종료
    echo "0 = ".$search[0];
    echo "<br />";
    echo "1 = ".$search[1];
    echo "<br />";
    echo "2 = ".$search[2];
    echo "<br />";
    echo "3 = ".$search[3];
    echo "<br />";
    echo "4 = ".$search[4];
    echo "<br />";
    echo "5 = ".$search[5];
    echo "<br />";
    echo "6 = ".$search[6];
    echo "<br />";

}    // While 문 종료
fclose ($file);

?>

블로그 이미지

Link2Me

,
728x90

PHP 에서 폴더(디렉토리)내에 특정 파일만 지우는 걸 해야 할 일이 있어서

인터넷 검색하여 여러자료를 토대로 원하는 내용을 만들어서 테스트를 해보고 개념을 잡았다.


if($fileExt == 'csv') 에서 처리할 사항이 있어서 테스트 해봤는데 파일 다루는데 많은 도움이 되었다.

리눅스 명령어 `rm -rf 디렉토리명`;

리눅스 명령어 `rm -rf 파일명`;    // `는 키보드 상의 왼쪽 위 물결(~)키와 함께 있는 기호

을 PHP 코드에 넣어서 파일을 실행해보니 권한이 없는 것도 그냥 지워버린다.


파일의 소유권자가 root 인 경우에는 @chmod($_tempdfile,0707); 로 파일의 모드 변경을 시도해도 웹은 사용자이므로 권한 변경이 안된다.  Owner 를 apache 로 변경해줘야만 변경이 된다.


아래 코드에서 가장 핵심적인 사항은 unlink 는 파일을 지우는 함수인데, unlink(파일명) 이렇게 하면 안되고

unlink(경로+파일명) 으로 해야 지워진다.

파일을 읽어서 프로세스를 처리하고 나서 파일을 지울 때는 읽어드린 파일명과 경로를 포함해서 unlink 하면 바로 바로 지워지므로 서버에 불필요한 자료가 남지 않는다.


<?php
// 파일의 크기 구하기
foreach (glob("*.csv") as $filename) {
    echo "$filename size " . filesize($filename) . "\n";
    echo "<br />";
}
echo "<br />";

// 폴더내 파일 전부 구하기
echo "<br />";
$dir = './';
$files = scandir($dir);
 
foreach ($files as $ind_file) {
  if (is_file($ind_file)) {
    ?>
    <li><?php echo $ind_file;?> </li>
    <?php
  }
}


// 디렉토리에 있는 파일과 디렉토리의 갯수 구하기
$path = opendir("./"); // opendir 함수를 이용해서 현재 디렉토리의 핸들을 얻어옴

// readdir함수를 이용해서 현재 디렉토리에 있는 디렉토리와 파일들의 이름을 배열로 읽어들임
while($file=readdir($path)) {    
    if($file=="."||$file=="..") continue; // file명이 ".", ".." 이면 무시함
    $fileInfo = pathinfo($file);
    print_r($fileInfo);  // 파일 경로 정보가 어떻게 되는지 확인하기 위해 출력
    echo "<br />";
    $fileExt = $fileInfo['extension']; // 파일의 확장자를 구함

    if (empty($fileExt)){
        $dir_count++; // 파일에 확장자가 없으면 디렉토리로 판단하여 dir_count를 증가시킴
    } elseif($fileExt == 'csv') {
        $csv_count++;  // 파일 확장자가 CSV 이면 csv_count를 증가시킴
        $_tmpdfile = $path.$file;
        @chmod($_tempdfile,0707);    // 파일의 소유권이 있는 경우에만 권한변경
        $cmd = `rm -rf *.csv`;    // 파일의 소유권에 상관없이 파일 모두 삭제처리
        if(is_writable($_tmpdfile)) {
            unlink($_tmpdfile);
            echo "파일 삭제됨"."<br />";
        } else {
            echo "파일 쓰기(삭제) 권한 없음"."<br />";
        }
       
    } else {
        $file_count++;  // 파일에 확장자가 있으면 file_count를 증가시킴
    }

}
@closedir($path);

echo "<br />";
echo "subfolder 수는 : ".$dir_count."<br />";
echo "CSV 파일의 갯수는 : ".$csv_count."<br />";
echo "파일의 갯수는 : ".$file_count;
echo "<br />";

// 폴더내 파일 전부 구하기
echo "<br />";
$dir = './';
$files = scandir($dir);
 
foreach ($files as $ind_file) {
  if (is_file($ind_file)) {
    ?>
    <li><?php echo $ind_file;?></li>
    <?php
  }
}

?>

블로그 이미지

Link2Me

,
728x90

[PHP] 파일 삭제


PHP에서 파일삭제하는 방법이다.

파일명을 적을 때 반드시 어떤 경로에 있는지를 포함해야 한다.



<?php
$filename = './datafile.csv';  // ./ 이란 것은 현재 디렉토리를 의미
if(is_file($filename)) {
    if(is_writable($filename)) {
        unlink($filename);  //파일삭제(절대경로 "/" 불가능)
        echo '파일 삭제됨.';
    } else {
        echo '파일에 대한 쓰기(삭제) 권한 없음.';
    }
} else {
    echo '파일이 없음.';
}

?>

블로그 이미지

Link2Me

,
728x90

DB 내용을 화면에 출력(이중 for 문)



DB 테이블에 저장된 게시물을 불러다가 화면에 출력하는 PHP 소스이다.

우선 DB에 저장되는 데이터는 <br> 태그로 행구분을 하여 저장한다는 걸 알아야 한다.

파일에서 가져온 걸 분리할 때에는 fgetcsv 함수를 이용하고, Encoding 옵션 등을 처리할 수 있게 조치하면 된다.

행간의 구분은 explode 함수를 사용하여 Line 단위로 구분한다.

최대 몇행인지는 count($lines) 로 파악하고,

이제 한 행에서 구분자로 다시 explode 함수를 이용하여 구분한다.

for 문 안에 for 문은 필요하면 사용하고 필요하지 않으면 사용하지 않아도 된다.

$line 배열은 $line[0], $line[1] 등으로 분리된다. 이 값으로 원하는 결과를 다시 만들어낼 수도 있다.


<?php
////////////////////////////////////////////////////////////////
$lines = explode("<br>", $R['content']);    // line 단위로 분리
for ( $i=0; $i < count($lines) ; $i++) {
    $line = explode(";", $lines[$i]);    // 구분자 기준으로 분리
    for($j=0 ; $j < count($line) ; $j++) {
        if($line[$j] != "") echo $line[$j]."/";
    }
    echo "<br>";
}
?>


for(초기식; 조건식; 종결식){  // for반복문은 반복되는 횟수에 비중이 있다

     반복될 문장 

}

초기식 -> 처음 문장을 실행시킬때 대입시킬 값

조건식 -> 언제까지 실행할지 범위를 지정

종결식 -> 처음값이 조건식에 대해 맞출수있게끔 하나씩 증가/감소



블로그 이미지

Link2Me

,
728x90

MySQL DB 중복여부 검사하여 없는 것만 추가


자료를 DB에 입력하는 걸 좀 편하게 하려고 중복검사 루틴을 만들어서 테스트를 했는데 계속 자료가 중복으로 들어가 저장된다.

서버 DB 자료를 엑셀로 내보내기 해서 중복검사를 하면 중복된 데이터는 전부 체크하여 표시를 해준다.

어디서 잘못된 걸까? 계속 머리 싸매다가 네이버 검색으로 하는데 자료 찾아도 잘 안나온다.

구글링을 해서 찾았더니 뭔가 힌트가 될만한 것이 검색된다.

넣어서 검사를 했더니 제대로 중복검사 여부를 체크한다.

WHERE eng = '".addslashes($line[0])."'

바로 이 부분 때문에 중복검사를 제대로 못했던 거다.

물론 '(Apostrophe) and " (Quotation mark) 가 없는 한글은 WHERE han = '$line[1]' 으로 검사해도 중복체크를 잘 한다.

중복검사 하는 가장 핵심적인 팁이라 할 수 있는 걸 찾게 되어 너무 기쁘다.


<?
$DB_CONNECT = isConnectDb($DB);
########### DB 연결 ###########
$file=fopen("insert_data.csv","r");
if(!$file){
    echo("Failed to open the file");
    exit;
}

while($line = fgetcsv($file,1000, ";")) { // 구분자는 ; 로 지정, 한줄씩 읽어드린 값을 끝라인까지 계속하라.
    $query = mysql_query("SELECT uid, eng FROM engtable WHERE eng = '".addslashes($line[0])."'",$DB_CONNECT);
    $dupcheck = mysql_fetch_array($query);
    if ($dupcheck['uid']) {
           $dup_line ++;
    } else {     // 중복된 자료가 없을 경우
        $eng = addslashes(trim($line[0]));    // 쿼터(')의 경우 역슬래쉬(\) 처리해야 DB에 저장됨

        $sql = "INSERT INTO $tblName (uid,eng,kor) VALUES (NULL,'$eng','$kor')";
        mysql_query($sql,$DB_CONNECT); // MYSQL DB에 저장
        $ok ++;
        if (($ok % 500) == 0) {
            echo(" $ok 건 저장");
            flush();
            sleep(3); //500개 저장할때마다 3초씩 쉰다.
        }
    $total_line++;
    } //중복체크 END 문
}

if ($dup_line > 0) {
    echo("중복 $dup_line 건 있음");
    echo "<br>";
}
echo("총 $total_line 자료 추가");
fclose ($file);
?>

블로그 이미지

Link2Me

,