시소당
게시판용 라이브러리 입니다
소스가 꽤 안정화 됐기 때문에 공개합니다.
역시 LGPL이구요.
LGPL을 꼭 읽어보시고 사용해주시기 바랍니다.
다수의 DB밴더라이브러리를 지원하는 DB클래스와 기타 유틸리티가
들어있습니다.
개선의견 많이 많이 주시면 감사하겠습니다.
<?
/**
* @fileoverview addictlib
* <br>Copyrights ⓒ 2006 GWKPLUS All rights reserved.
* 이 소스는 Addict 프레임워크의 일부분이며 LGPL을 따릅니다.
* @author gwkplus gwkplus@gmail.com
* @version 0.1
*/
require "PreparedStatement.php";
/**
* 데이터소스연결문자열을 해석하여 배열로 반환
* @param string
$datasource 데이터소스 문자열
* @return array
$ds
* @author gwkplus
*/
function dsparse(
$datasource)
{
$ds = array();
$datasource = split("://",
$datasource);
$ds[dbvender] =
$datasource[0];
$datasource = split(":",
$datasource[1]);
$ds[hostname] =
$datasource[0];
$datasource = split("/",
$datasource[1]);
$ds[port] =
$datasource[0];
$ds[dbname] =
$datasource[1];
return
$ds;
}
/**
* 범용 SQL 제한절 만들기
* @return string 쿼리 문자열
* @param string
$dbvender 데이터베이스 벤더명
* @param string
$sql 쿼리 문자열
* @param number
$offset 오프셋 번호
* @param number
$count 갯수
* @param string
$rownumname 로우번호 필드명
* @author gwkplus
*/
function addLimitStmt(
$dbvender,
$sql,
$offset,
$count,
$rownumname="")
{
$offset_count =
$offset +
$count;
$rnd = "
$offset"."_"."
$count";
if(
$offset < 0)
{
$offset = 0;
}
if(
$count < 0)
{
$count = 0;
}
switch(
$dbvender)
{
case "pgsql":
case "mysql":
{
$sql = "
$sql limit
$offset,
$count";
break;
}
case "mssql":
{
$sql =
<<<HEREDOC
select top
$count *
from
(
select top
$offset_count *
from
(
$sql
) AS subquery1_
$rnd
order by
$rownumname desc
) AS subquery2_
$rnd
order by
$rownumname asc
HEREDOC;
break;
}
case "oracle":
{
$count =
$offset +
$count;
$offset += 1;
$sql =
<<<HEREDOC
select *
from
(
select rownum as numrow_
$rnd, subquery1_
$rnd.*
from
(
$sql
) AS subquery1_
$rnd
)
where
numrow_
$rnd between
$offset
and
$count
HEREDOC;
break;
}
}
return
$sql;
}
/**
* @author gwkplus
*/
class AddictDB
{
private
$link = null;
private
$ds = null;
private
$pass = null;
public
$lastQuery = null;
/**
* 생성자
* @param string
$ds 데이터소스 문자열
* @param string
$user 사용자명
* @param string
$pass 비밀번호
* @author gwkplus
*/
public function __construct(
$ds,
$user,
$pass)
{
$this->ds = dsparse(
$ds);
$this->ds[user] =
$user;
$this->pass =
$pass;
$this->connect();
}
/**
* 데이터베이스 연결 함수
* @return object 데이터베이스 연결 객체
* @author gwkplus
*/
public function connect()
{
switch(
$this->ds[dbvender])
{
case "mysql" :
{
$this->link = mysqli_connect(
$this->ds[host],
$this->ds[user],
$this->pass);
break;
}
case "mssql" :
{
$this->link = mssql_connect(
$this->ds[host],
$this->ds[user],
$this->pass);
break;
}
case "odbc" :
{
$this->link = odbc_connect(
$this->ds[host],
$this->ds[user],
$this->pass);
break;
}
}
$this->select_db(
$this->ds[dbname]);
return
$this->link;
}
/**
* 데이터베이스 선택 함수
* @param string
$dbname 데이터베이스명
* @return boolean true = 연결 성공, false = 연결 실패
* @author gwkplus
*/
public function select_db(
$dbname)
{
switch(
$this->ds[dbvender])
{
case "mysql" :
{
return mysqli_select_db(
$this->link,
$dbname);
}
case "mssql" :
{
return mssql_select_db(
$dbname,
$this->link);
}
case "odbc" :
{
$this->query("use
$dbname");
return true;
}
}
return false;
}
/**
* 데이터베이스용 특수문자 처리
* @param string
$escapestr 처리할 문자열
* @return string 처리된 문자열
* @author gwkplus
*/
public function escape_string(
$escapestr)
{
return mysqli_real_escape_string(
$this->link,
$escapestr);
}
/**
* 트랜잭션을 시작합니다.
* @return boolean true = 성공, false = 실패
* @author gwkplus
*/
function beginTran()
{
switch(
$this->ds[dbvender])
{
case "mysql":
{
$this->query("BEGIN");
return true;
}
case "mssql":
{
$this->query("BEGIN TRANSACTION");
return true;
}
case "odbc":
{
odbc_autocommit(
$this->link, false);
return true;
}
}
}
/**
* 트랙잭션을 완료합니다.
* @return boolean true = 성공, false = 실패
* @author gwkplus
*/
function commitTran()
{
switch(
$this->ds[dbvender])
{
case "mysql":
{
$this->query("COMMIT");
return true;
}
case "mssql":
{
$this->query("COMMIT TRANSACTION");
return true;
}
case "odbc":
{
odbc_commit(
$this->link);
odbc_autocommit(
$this->link, true);
return true;
}
}
}
/**
* 트랜잭션을 취소합니다.
* @return boolean true = 성공, false = 실패
* @author gwkplus
*/
function rollbackTran()
{
switch(
$this->ds[dbvender])
{
case "mysql":
{
$this->query("ROLLBACK");
return true;
}
case "mssql":
{
$this->query("ROLLBACK TRANSACTION");
return true;
}
case "odbc":
{
odbc_rollback(
$this->link);
return true;
}
}
}
/**
* 쿼리 함수
* @param string
$query 쿼리문자열
* @return mixed 각 DB쿼리 함수의 실행결과를 돌려줌
*/
public function query(
$query)
{
$this->lastQuery =
$query;
switch(
$this->ds[dbvender])
{
case "mysql" :
{
return mysqli_query(
$this->link,
$query);
}
case "mssql" :
{
return mssql_query(
$query,
$this->link);
}
case "odbc" :
{
return odbc_exec(
$this->link,
$query);
}
}
return false;
}
/**
* 쿼리 실행후 결과를 배열에 담아 반환.
* @param string
$query 쿼리 문자열
* @return array 결과 배열
* @author gwkplus
*/
public function query_fetch_row(
$query)
{
$result =
$this->query(
$query);
if(
$result == null)
{
return null;
}
$row =
$this->fetch_row(
$result);
return
$row;
}
/**
* 결과 포인터에서 데이터를 추출해서 배열로 반환.
* @param mixed
$result 결과 포인터
* @return array 결과 데이터 배열
* @author gwkplus
*/
public function fetch_row(
$result)
{
switch(
$this->ds[dbvender])
{
case "mysql":
{
return mysqli_fetch_row(
$result);
}
case "mssql":
{
return mssql_fetch_row(
$result);
}
case "odbc":
{
return odbc_fetch_row(
$result);
}
}
}
/**
* 결과 포인터로 부터 결과수를 가져온다.
* @param mixed
$result 결과 포인터
* @return int 결과행의 수를 가져온다.
*/
public function num_rows(
$result)
{
switch(
$this->ds[dbvender])
{
case "mysql":
{
return mysqli_num_rows(
$result);
}
case "mssql":
{
return mssql_num_rows(
$result);
}
case "odbc":
{
return odbc_num_rows(
$result);
}
}
}
/**
* 이전 연산에서 영향받은 로우 갯수 반환
* @param mixed
$result 결과 포인터
* @return int 영향받은 행의 수를 반환
*/
public function affected_rows(
$result)
{
switch(
$this->ds[dbvender])
{
case "mysql":
{
return mysqli_affected_rows(
$this->link);
}
case "mssql":
{
return mssql_rows_affected(
$result);
}
case "odbc":
{
return odbc_num_rows(
$result);
}
}
}
/**
* 결과 포인터의 메모리를 해제 한다.
* @param mixed
$result 결과 포인터
* @return void
*/
public function free_result(
$result)
{
switch(
$this->ds[dbvender])
{
case "mysql":
{
mysqli_free_result(
$result);
}
case "mssql":
{
mssql_free_result(
$result);
}
case "odbc":
{
odbc_free_result(
$result);
}
}
}
/**
* 쿼리를 실행하고 결과를 관계배열로 반환한다.
* @param string
$query 쿼리문자열
* @return array 관계배열
*/
public function query_fetch_assoc(
$query)
{
$result =
$this->query(
$query);
if(
$result==null)
{
return null;
}
$row =
$this->fetch_assoc(
$result);
return
$row;
}
public function fetch_assoc(
$result)
{
switch(
$this->ds[dbvender])
{
case "mysql" :
{
return mysqli_fetch_assoc(
$result);
}
case "mssql" :
{
return mssql_fetch_assoc(
$result);
}
case "odbc" :
{
return odbc_fetch_array(
$result);
}
}
return null;
}
public function addLimitStmt(
$sql,
$offset,
$count,
$rownumname = "")
{
return addLimitStmt(
$this->ds[dbvender],
$sql,
$offset,
$count,
$rownumname);
}
}
/**
* 태그 모음
*/
function inputradio(
$name,
$value,
$checked,
$attributes)
{
if(
$checked == true)
$checked = "checked";
else
{
$checeked = "";
}
return "<input type=radio name='
$name' value='
$value'
$attributes $checked>";
}
function selectoption(
$value,
$text,
$selected,
$attributes)
{
return "<option value='
$value'
$attributes $checked>
$text</option>";
}
/**
* 공용페이징 계산기
* @param int
$resultcount 결과수
* @param int
$listlimit 목록제한수
* @param int
$pagelimit 페이지제한수
* @param int
$pageno 현재 페이지 번호
* @return string 페이징계산에 필요한 변수를 관계배열로 반환
* @author gwkplus
*/
function pagingCalc(
$resultcount,
$listlimit,
$pagelimit,
$pageno)
{
$p = array();
// 총페이지수
$p['total_page'] = (int)((
$resultcount - 1)/
$listlimit) + 1;
// 현제 페이지번호
$p['pageno'] = (
$pageno < 1) ? 1 : ((
$pageno >
$p['total_page']) ?
$p['total_page'] :
$pageno);
// 이전 페이지 번호
$p['prev_page'] =
$p['pageno'] > 1 ?
$p['pageno']-1 : 0;
// 다음 페이지 번호
$p['next_page'] =
$p['pageno'] <
$p['total_page'] ?
$p['pageno'] + 1 : 0;
// 목록 처음 페이지 번호
$p['startpage_list'] = (int)((
$p['pageno'] - 1) /
$pagelimit) *
$pagelimit + 1;
// 목록 마지막 페이지 번호
$p['endpage_list'] =
$p['total_page'] > (
$p['startpage_list'] +
$pagelimit-1) ?
$p['startpage_list'] +
$pagelimit - 1 :
$p['total_page'];
// 다음 페이지 목록
$p['prev_pagelist'] =
$p['startpage_list'] == 1 ? 0 :
$p['startpage_list'] - 1;
// 이전 페이지 목록
$p['next_pagelist'] =
$p['total_page'] ==
$p['endpage_list'] ? 0 :
$p['endpage_list'] + 1;
$p['resultcount'] =
$resultcount;
$p['listlimit'] =
$listlimit;
$p['pagelimit'] =
$pagelimit;
return
$p;
}
/**
* 페이징링크와 관련 정보를 받아서 페이징 링크 문자열로 반환
* @param string
$baseUrl 기반 링크 주소
* @param int
$resultcount 결과수
* @param int
$listlimit 목록제한수
* @param int
$pagelimit 페이지제한수
* @param int
$pagelistlimit 페이징목록제한수
* @param int
$pageno 현재 페이지 번호
* @return string 페이징 링크 문자열
* @author gwkplus
*/
function paging(
$baseUrl,
$resultcount,
$listlimit,
$pagelimit,
$pagelistlimit ,
$pageno)
{
$ret_val = "";
$p = pagingCalc(
$resultcount,
$listlimit,
$pagelimit ,
$pageno);
// 페이징===============================================================================
if(
$p['prev_page'] > 0)
{
$link = '<a href="?" title="이전 페이지로 이동합니다.">[이전]</a>';
$pstmt = new PreparedStatement(
$link);
$pstmt->setEval(0,
$baseUrl . '&pageno=' .
$p['prev_page']);
$ret_val .=
$pstmt->toString();
$pstmt = null;
}
else
{
$ret_val .= '<a title="">[이전]</a>';
}
if(
$p['prev_pagelist'] > 0)
{
$link = ' <a href="?" title="?페이지로 이동합니다.">[이전목록]</a> ';
$pstmt = new PreparedStatement(
$link);
$pstmt->setEval(0,
$baseUrl . '&pageno=' .
$p['prev_pagelist']);
$pstmt->setInt(0,
$p['prev_pagelist']);
$ret_val .=
$pstmt->toString();
$pstmt = null;
}
if(
$pageno>
$pagelimit)
{
$link = '<a href="?" title="첫 페이지로 이동합니다.">[1]</a> ... ';
$pstmt = new PreparedStatement(
$link);
$pstmt->setEval(0,
$baseUrl . '&pageno=1');
$ret_val .=
$pstmt->toString();
$pstmt = null;
}
$page_link = "";
for(
$i =
$p['startpage_list'];
$i <=
$p['endpage_list'];
$i++)
{
$page_link = ' <a href=? title="?페이지로 이동합니다.">?</a> ';
$pstmt = new PreparedStatement(
$page_link);
$pstmt->setString(0,
$baseUrl . '&pageno=' .
$i);
$pstmt->setInt(0,
$i);
if(
$i ==
$pageno)
{
$pstmt->setEval(0, "[
$i]");
}
else
{
$pstmt->setEval(0, "
$i");
}
$ret_val .=
$pstmt->toString();
$pstmt = null;
}
if(
$p['startpage_list'] +
$pagelimit <=
$p['total_page']
&& (
$p['endpage_list'] <
$pagelistlimit ||
$pagelistlimit == 0))
{
if(
$pagelistlimit != 0)
{
$p['total_page'] =
$pagelistlimit;
}
$link = ' ... <a href="?" title="마지막(?) 페이지로 이동합니다.">?</a> ';
$pstmt = new PreparedStatement(
$link);
$pstmt->setEval(0,
$baseUrl . '&pageno=' .
$p['total_page']);
$pstmt->setInt(0,
$p['total_page']);
$pstmt->setInt(0,
$p['total_page']);
$ret_val .=
$pstmt->toString();
$pstmt = null;
}
if(
$p['next_pagelist'] > 0
&& (
$p['endpage_list'] <
$pagelistlimit ||
$pagelistlimit == 0))
{
$link = ' <a href="?" title="?페이지로 이동합니다.">[다음목록]</a> ';
$pstmt = new PreparedStatement(
$link);
$pstmt->setEval(0,
$baseUrl . '&pageno=' .
$p['next_pagelist']);
$pstmt->setInt(0,
$p['next_pagelist']);
$ret_val .=
$pstmt->toString();
$pstmt = null;
}
if(
$p['next_page'] > 0
&& (
$pageno <
$pagelistlimit ||
$pagelistlimit == 0))
{
$link = '<a href="?" title="다음 페이지로 이동합니다.">[다음]</a>';
$pstmt = new PreparedStatement(
$link);
$pstmt->setEval(0,
$baseUrl . '&pageno=' .
$p['next_page']);
$ret_val .=
$pstmt->toString();
$pstmt = null;
}
else
{
$ret_val .= '<a title="">[다음]</a>';
}
// 페이징===============================================================================
$p = null;
return
$ret_val;
}
/**
* HTTP 인증 헤더를 해석하는 함수
* @author gwkplus
*/
function http_digest_parse(
$txt)
{
// protect against missing data
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();
preg_match_all('@(\w+)=(?:([\'"])([^\2]+)\2|([^\s,]+))@',
$txt,
$matches, PREG_SET_ORDER);
foreach (
$matches as
$m) {
$data[
$m[1]] =
$m[3] ?
$m[3] :
$m[4];
unset(
$needed_parts[
$m[1]]);
}
return
$needed_parts ? false :
$data;
}
/**
* HTTP 인증 요구 헤더들을 전송합니다.
* @author gwkplus
*/
function sendHttpAuthHeaders(
$realm)
{
$nonce = "Ny8yLzIwMDIgMzoyNjoyNCBQTQ";
header('HTTP/1.0 401 Unauthorized');
Header("WWW-authenticate: basic realm=\"
$realm\"");
//Header("WWW-Authenticate: Digest realm=\"
$realm\", nonce=\"
$nonce\", algorithm=MD5, qop=\"auth\"");
}
/**
* HTTP 이어받기를 위한 헤더들을 전송합니다.
* @author gwkplus
*/
function sendHttpRangeHeaders(
$filepath,
$filename="",
$seek_start=0)
{
$filesize = filesize(
$filepath);
$filesize_1 =
$filesize-1;
$filedate = gmdate('D, d M Y H:i:s \G\M\T', filemtime(
$filepath));
header("Last-Modified:
$filedate");
header("Accept-Ranges: bytes");
if(
$filename != "")
{
}
else
{
}
header("content-disposition: attachment; filename=\"
$filename\"");
header("Content-Length: " . (
$filesize-
$seek_start));
/**
* TODO LIST
* . unique 하면서도 바뀌지 않는 id를 만들어보자.
* header("ETag: \"6c02b-2cb3f52-68a29e00\"");
*/
if(
$seek_start > 0
&&
$seek_start <
$filesize_1)
{
header("Content-Range: bytes
$seek_start-
$filesize_1/
$filesize");
}
header("Content-Type: application/unknown");
return true;
}
/**
* 사이즈를 읽기 형식으로 반환합니다.
* @param int
$size 바이트 사이즈
* @author gwkplus
*/
function addict_toHumanSize(
$size)
{
$G = (1024*1024*1024);
$M = (1024*1024);
$K = (1024);
$type = "";
$size = (float)
$size;
if(
$size >=
$G)
{
$size = (float)(
$size)/
$G;
$type = "G";
}
else if(
$size >=
$M)
{
$size = (float)(
$size)/
$M;
$type = "M";
}
else if(
$size >=
$K)
{
$size = (float)(
$size)/
$K;
$type = "K";
}
else
{
$type = "K";
}
$pos = strpos(
$size, ".");
if(
$pos > 0)
{
$size = substr(
$size,0,
$pos+3);
}
return
$size.
$type;
}
/**
* DiskUsage
* @param string
$path 경로 문자열
* @param string
$option 옵션
* @return 디스크 사용량을 반환합니다.
* @author gwkplus
*/
function addict_du(
$path,
$option = "")
{
$ret_val = exec("du -s
$option $path");
$ret_val = split("\t",
$ret_val);
$ret_val =
$ret_val[0];
if(
$ret_val == "") return "0K";
return
$ret_val;
}
/**
* 지정한 경로의 파일개수를 반환 합니다.
* @param string
$path 경로 문자열
* @param string
$option 옵션 문자열
* @return int 파일갯수
* @author gwkplus
*/
function addict_filecount(
$path = ".",
$option = "-")
{
if(
$option != "d")
{
$option = "-";
}
$ret_val = exec("ls -AlR
$path | grep \"^
$option\" | wc -l");
if(
$ret_val == "") return 0;
return
$ret_val;
}
/**
* 둥근 외곽선
* @author gwkplus
*/
function addict_getRoundBorder(
$imgUrl,
$size,
$style = "")
{
if(
$style!="")
{
return
<<<HEREDOC
<table id="
$randomid" border=0 cellpadding=0 cellspacing=0
$event style="
$style">
<tr>
<td width=
$size height=
$size style="background:url(
$imgUrl/slt.jpg)"></td>
<td height=
$size style="background:url(
$imgUrl/st.jpg)"></td>
<td width=
$size height=
$size style="background:url(
$imgUrl/srt.jpg)"></td>
</tr>
<tr>
<td width=
$size style="background:url(
$imgUrl/sl.jpg)"></td>
<td>
HEREDOC;
}// end if
return
<<<HEREDOC
</td>
<td width=
$size style="background:url(
$imgUrl/sr.jpg)"></td>
</tr>
<tr>
<td width=
$size height=
$size style="background:url(
$imgUrl/slb.jpg)"></td>
<td height=
$size style="background:url(
$imgUrl/sb.jpg)"></td>
<td width=
$size height=
$size style="background:url(
$imgUrl/srb.jpg)"></td>
</tr>
</table>
HEREDOC;
}// end function
/**
* 주민등록 번호로 나이를 계산합니다.
* 주의)만 나이 계산이 아님
*/
function addict_pidAge(
$pid1,
$pid2)
{
if(
$pid1 == "")
{
return 0;
}
$pid =
$pid1.
$pid2;
$year = (int)(
$pid[0].
$pid[1]);
$sex = 6;
if(
$pid[
$sex] == 1
||
$pid[
$sex] == 2)
{
$year += 1900;
}
else if(
$pid[
$sex] == 3
||
$pid[
$sex] == 4)
{
$year += 2000;
}
$age = (int)date("Y")-
$year;
return
$age;
}
function addict_pidcheck(
$pid1,
$pid2="")
{
$mod = array();
$mod[0] = 31;
$mod[1] = 29;
$mod[2] = 31;
$mod[3] = 30;
$mod[4] = 31;
$mod[5] = 30;
$mod[6] = 31;
$mod[7] = 31;
$mod[8] = 30;
$mod[9] = 31;
$mod[10] = 30;
$mod[11] = 31;
$sex = 6;
$check = 12;
$pid =
$pid1.
$pid2;
$checknums = "234567892345";
if(strlen(
$pid)==13)
{
/**
* 성별체크
*/
if(
$pid[
$sex] > 4
||
$pid[
$sex] < 1)
{
return false;
}
/**
* 년월일 체크
*/
$month = (int)(
$pid[2].
$pid[3]);
$day = (int)(
$pid[4].
$pid[5]);
if(
$month > 12
||
$month < 1
||
$mod[
$month] <
$day
||
$day < 1)
{
return false;
}
/**
* 주민등록 번호 체크섬 확인
*/
return true; // 체크섬 사용안함
$sum = 0;
for(
$i = 0;
$i<13;
$i++)
{
$sum += (
$pid[
$i]*
$checknums[
$i]);
}
if((
$sum%11) == 0)
{
return 1 ==
$pid[
$check];
}
return (11-(
$sum%11) ==
$pid[
$check]);
}
return false;
}// end function
function addict_sendmail(
$to,
$from,
$subject,
$message,
$contentType = "text/html")
{
$headers = "From:
$from\n";
$headers .= "Content-Type: text/html; charset=ks_c_5601-1987\n";
$headers .= "Content-Transfer-Encoding: base64\n";
$subject = "=?ks_c_5601-1987?B?".base64_encode(
$subject)."?=";
$message = base64_encode(
$message);
mail(
$to,
$subject,
$message,
$headers);
}// end function
/*
class Exception
{
protected
$message = 'Unknown exception'; // exception message
protected
$code = 0; // user defined exception code
protected
$file; // source filename of exception
protected
$line; // source line of exception
function __construct(
$message = null,
$code = 0);
final function getMessage(); // message of exception
final function getCode(); // code of exception
final function getFile(); // source filename
final function getLine(); // source line
final function getTrace(); // an array of the backtrace()
final function getTraceAsString(); // formated string of trace
//Overrideable
function __toString(); // formated string for display
}
*/
class MyException extends Exception
{
// 예외를 재정의해, 메세지를 옵션은 아니고 한다
public function __construct(
$message,
$code = 0) {
// 하등의 코드
// 모두를 올바르고 확실히 대입한다
parent::__construct(
$message,
$code);
}
// 오브젝트의 문자열 표현을 독자적으로 정의한다
public function __toString() {
return __CLASS__ . ": [{
$this->code}]: {
$this->message}n";
}
}
?>
출처 : http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=55800&sca=&sfl=wr_subject%7C%7Cwr_content&stx=php5&sop=and