This commit is contained in:
Jaybe
2025-03-05 14:02:29 +09:00
commit 247a7808d3
357 changed files with 161196 additions and 0 deletions
View File
+74
View File
@@ -0,0 +1,74 @@
<?php
namespace App\Libraries;
class Calc {
public static function cpc($spend, $inline_link_clicks) { //CPC(Cost Per Click: 클릭당단가 (1회 클릭당 비용)) = 지출액/링크클릭
if($inline_link_clicks > 0)
return round($spend / $inline_link_clicks);
return 0;
}
public static function ctr($inline_link_clicks, $impression) { //CTR(Click Through Rate: 클릭율 (노출 대비 클릭한 비율)) = (링크클릭/노출수)*100
if($impression > 0)
return round(($inline_link_clicks / $impression)*100, 2);
return 0;
}
// public static function sales($unique, $db_price) { //매출액 = CPA단가 * 유효 DB
// if($unique > 0)
// return round($unique * $db_price);
//
// return 0;
// }
// public static function margin($sales, $spend, $shortterm) { //수익 = 매출액(CPA단가*유효 DB) - 지출액
// $shortterm_val = "0.".$shortterm;
//
// if($spend > 0){
// if($shortterm > 0){
// $result = $spend * $shortterm_val;//^ 뒤에 값이 있으면 수익 계산 다르게
// }
// else{
// $result = $sales - $spend;
// }
// }
// return round($result);
// }
public static function margin_ratio($margin, $sales) { //수익률 = (수익/매출액)*100
if($sales > 0) {
$result = ($margin / $sales)*100;
return round($result,2);
}
return 0;
}
public static function cpa($unique, $spend) { //CPA(Cost Per Action: DB단가(전환당 비용)) = 지출액/유효db
if($unique > 0){
$result = $spend / $unique;
return round($result);
}
return 0;
}
public static function cvr($unique, $inline_link_clicks) { //CVR(Conversion Rate:전환율 = (유효db / 링크클릭)*100
if($inline_link_clicks > 0)
return round(($unique / $inline_link_clicks)*100, 2);
return 0;
}
// public static function cvc($spend, $inline_link_clicks) { //Conversion Cost 전환단가 = 지출액/클릭
// if($inline_link_clicks > 0)
// return round($spend / $inline_link_clicks);
//
// return 0;
// }
}
?>
+100
View File
@@ -0,0 +1,100 @@
<?php
namespace App\Libraries\Douzone;
use App\Controllers\BaseController;
use App\Libraries\Douzone\DouzoneModel;
use PHPHtmlParser\Dom;
use App\Libraries\slack_api\SlackChat;
class Douzone extends BaseController {
private $douzone;
public function __construct()
{
$this->douzone = new DouzoneModel();
}
public function getDayOff() { //연차
$list = $this->douzone->getDayOff();
$result = [];
foreach($list as $row) {
$desc = $this->getDayOffDesc($row);
// dd($desc);
foreach($desc as $v) {
if(preg_match('/시간차/', $row['doc_title']) || preg_match('/시간차/', $v['reason'])) continue;
preg_match_all('/(오전|오후)/', $v['reason'], $matches);
preg_match_all('/(오전|오후)/', $row['doc_title'], $titles);
if(isset($matches[1][0]) && $matches[1][0]) $v['type'] = $matches[1][0] . $v['type'];
else if(isset($titles[1][0]) && $titles[1][0]) $v['type'] = $titles[1][0] . $v['type'];
$data = [
'email' => $row['email_addr'] . "@carelabs.co.kr",
'name' => preg_replace('/^.+_(.+)$/', '$1', $row['user_nm']),
'title' => $row['doc_title'],
'status' => $row['doc_sts'],
'reg_time' => $row['rep_dt'],
'end_time' => $row['end_dt'],
'rep_dt' => $row['rep_dt'],
...$v
];
$result[] = $data;
}
}
// dd($result);
return $result;
}
private function getDayOffDesc($data) {
$xml = new DOM;
$xml->loadStr($data['doc_xml']);
$contents = new DOM;
$contents->loadStr($data['doc_contents']);
$info = $xml->find('div',0)->find('table thead td',0)->text();
preg_match_all('/([가-힣\s]+)\s\:\s([\d\.]+)/', $info, $m);
$total = [
'all' => $m[2][0],
'used' => $m[2][1],
'remain' => $m[2][2]
];
$rows = $xml->find('div',1)->find('table tbody',0)->find('tr');
$result = [];
foreach($rows as $row) {
$reason = trim($contents->find('table tbody')->find('tr',1)->find('td',1)->innerText());
if(trim($row->find('td',5)->text()))
$reason .= "/".trim($row->find('td',5)->text());
$result[] = [
'type' => trim($row->find('td',0)->text()), //근태구분
'start' => trim($row->find('td',1)->text()), //시작일자
'end' => trim($row->find('td',2)->text()), //종료일자
'used' => trim($row->find('td',4)->text()), //연차차감
'reason' => trim(str_replace("&nbsp;", " ", $reason)), //사유
'total' => $total
];
}
return $result;
}
public function getMemberList() { //그룹웨어 직원 목록
$list = $this->douzone->getMemberList();
$result = [];
foreach($list as $row) {
$div = explode("|", $row['path_name']);
if(empty($div[1])) $div[1] = $row['path_name'];
$division = $div[1];
$team = (isset($div[2])?$div[2]:$div[1]) .(isset($div[3])?"[{$div[3]}]":"");
$data = [
'email' => $row['email_addr'] . "@carelabs.co.kr",
'name' => $row['name'],
'position' => $row['position'],
'phone' => $row['phone'],
'division' => $division,
'team' => $team
];
$result[] = $data;
}
return $result;
}
public function sendToSlackForGetDayOff() {
$slack = new SlackChat();
$slack->sendMessage(['channel'=>'C05G82NMG8G','text'=>'message test']);
}
}
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace App\Libraries\Douzone;
use CodeIgniter\Model;
Class DouzoneModel extends Model {
private $zenith, $gwdb;
public function __construct()
{
$this->zenith = \Config\Database::connect();
$this->gwdb = \Config\Database::connect('gwdb');
}
public function getDayOff() {
$builder = $this->gwdb->table('viberc_gw AS gw');
$builder->select("usr.email_addr, gw.*, gwc.doc_contents, gwi.doc_xml");
$builder->join("v_user_info AS usr", "gw.user_id = usr.emp_seq", "left");
$builder->join("viberc_gw_contents AS gwc", "gw.doc_id = gwc.doc_id", "left");
$builder->join("viberc_gw_interlock AS gwi", "gw.doc_id = gwi.doc_id", "left");
$builder->where("gw.form_id", "18");
$builder->where("gw.doc_sts <=", 90); //90:결재완료
$builder->where("gw.rep_dt >= DATE_SUB(NOW(), INTERVAL 30 DAY)");
$builder->groupBy("gw.doc_id");
$builder->orderBy("gw.rep_dt", "desc");
// dd($builder->getCompiledSelect());
$result = $builder->get()->getResultArray();
return $result;
}
public function getMemberList() {
$builder = $this->gwdb->table('v_user_info AS usr');
$builder->select("email_addr, substring_index(emp_name, '_',-1) AS name, dpm.dp_name AS position, mobile_tel_num AS phone, path_name");
$builder->join("t_co_comp_duty_position_multi AS dpm", "usr.dept_duty_code = dpm.dp_seq");
$builder->like("emp_name", "DM_%");
$builder->where("erp_emp_num <>", "");
$builder->where("usr.use_yn", "Y");
$builder->orderBy("join_day", "ASC");
$result = $builder->get()->getResultArray();
return $result;
}
}
+200
View File
@@ -0,0 +1,200 @@
<?php
/**
* SMS 발송을 관장하는 메인 클래스이다.
*
* 접속, 발송, URL발송, 결과등의 실질적으로 쓰이는 모든 부분이 포함되어 있다.
*/
namespace App\Libraries;
class SMS
{
public static $icode_key = "ebc4a57d3d3ad772d196378ccb25d0b9";
public static $socket_host = "211.172.232.124";
public static $socket_port = 9201;
public static $Data = array();
public static $Result = array();
// SMS 서버 접속
public static function SMS_con($host, $port, $key)
{
self::$socket_host = $host;
self::$socket_port = $port;
self::$icode_key = $key;
}
public static function Init()
{
self::$Data = ""; // 발송하기 위한 패킷내용이 배열로 들어간다.
self::$Result = ""; // 발송결과값이 배열로 들어간다.
}
public static function Add($strDest, $strCallBack, $strCaller, $strSubject, $strURL, $strData, $strDate, $nCount)
{
// 개행치환
$strData = preg_replace("/\r\n/", "\n", $strData);
$strData = preg_replace("/\r/", "\n", $strData);
// 문자 타입별 Port 설정.
$sendType = strlen($strData) > 90 ? 1 : 0; // 0: SMS / 1: LMS
if ($sendType == 0) $strSubject = "";
$strCallBack = CutChar($strCallBack, 12); // 회신번호
/** LMS 제목 **/
/*
제목필드의 값이 없을 경우 단말기 기종및 설정에 따라 표기 방법이 다름
1.설정에서 제목필드보기 설정 Disable -> 제목필드값을 넣어도 미표기
2.설정에서 제목필드보기 설정 Enable -> 제목을 넣지 않을 경우 제목없음으로 자동표시
제목의 첫글자에 "<",">", 개행문자가 있을경우 단말기종류 및 통신사에 따라 메세지 전송실패 -> 글자를 체크하거나 취환처리요망
$strSubject = str_replace("\r\n", " ", $strSubject);
$strSubject = str_replace("<", "[", $strSubject);
$strSubject = str_replace(">", "]", $strSubject);
*/
$strSubject = CutChar($strSubject, 30);
$strData = CutChar($strData, 2000);
$Error = CheckCommonTypeDest($strDest, $nCount);
$Error = IsVaildCallback($strCallBack);
$Error = CheckCommonTypeDate($strDate);
for ($i = 0; $i < $nCount; $i++) {
// $strDest[$i] = $strDest[$i];
$list = array(
"key" => self::$icode_key,
"tel" => $strDest[$i],
"cb" => $strCallBack,
"msg" => $strData,
"title" => $strSubject ? $strSubject : "",
"date" => $strDate ? $strDate : ""
);
$packet = json_encode($list);
self::$Data[$i] = '06' . str_pad(strlen($packet), 4, "0", STR_PAD_LEFT) . $packet;
}
return true;
}
/**
* 문자발송 및 결과정보를 수신합니다.
*/
public static function Send()
{
$fsocket = fsockopen(self::$socket_host, self::$socket_port, $errno, $errstr, 2);
if (!$fsocket) return false;
set_time_limit(300);
foreach (self::$Data as $puts) {
fputs($fsocket, $puts);
// while (!$gets) {
while (!isset($gets)) {
$gets = fgets($fsocket, 32);
}
$json = json_decode(substr($puts, 6), true);
$dest = $json["tel"];
if (substr($gets, 0, 20) == "0225 00" . FillSpace($dest, 12)) {
self::$Result[] = $dest . ":" . substr($gets, 20, 11);
} else {
self::$Result[$dest] = $dest . ":Error(" . substr($gets, 6, 2) . ")";
if (substr($gets, 6, 2) >= "80") break;
}
$gets = "";
}
fclose($fsocket);
self::$Data = array();
return true;
}
}
/**
* 원하는 문자열의 길이를 원하는 길이만큼 공백을 넣어 맞추도록 합니다.
*
* @param text 원하는 문자열입니다.
* size 원하는 길이입니다.
* @return 변경된 문자열을 넘깁니다.
*/
function FillSpace($text, $size)
{
for ($i = 0; $i < $size; $i++) $text .= " ";
$text = substr($text, 0, $size);
return $text;
}
/**
* 원하는 문자열을 원하는 길에 맞는지 확인해서 조정하는 기능을 합니다.
*
* @param word 원하는 문자열입니다.
* cut 원하는 길이입니다.
* @return 변경된 문자열입니다.
*/
function CutChar($word, $cut)
{
$word = substr($word, 0, $cut); // 필요한 길이만큼 취함.
for ($k = $cut - 1; $k > 1; $k--) {
if (ord(substr($word, $k, 1)) < 128) break; // 한글값은 160 이상.
}
$word = substr($word, 0, $cut - ($cut - $k + 1) % 2);
return $word;
}
/**
* 수신번호의 값이 정확한 값인지 확인합니다.
*
* @param strDest 발송번호 배열입니다.
* nCount 배열의 크기입니다.
* @return 처리결과입니다.
*/
function CheckCommonTypeDest($strDest, $nCount)
{
for ($i = 0; $i < $nCount; $i++) {
$strDest[$i] = preg_replace("/[^0-9]/", "", $strDest[$i]);
if (!preg_match("/^(0[173][0136789])([0-9]{3,4})([0-9]{4})$/", $strDest[$i])) return "수신번호오류";
}
}
/**
* 회신번호 유효성 여부조회
*
* @param string callback 회신번호
* @return 처리결과입니다
* 한국인터넷진흥원 권고사항
*/
function IsVaildCallback($callback)
{
$_callback = preg_replace('/[^0-9]/', '', $callback);
if (!preg_match("/^(02|0[3-6]\d|01(0|1|3|5|6|7|8|9)|070|080|007)\-?\d{3,4}\-?\d{4,5}$/", $_callback) &&
!preg_match("/^(15|16|18)\d{2}\-?\d{4,5}$/", $_callback)) {
return "회신번호오류";
}
if (preg_match("/^(02|0[3-6]\d|01(0|1|3|5|6|7|8|9)|070|080)\-?0{3,4}\-?\d{4}$/", $_callback)) {
return "회신번호오류";
}
}
/**
* 예약날짜의 값이 정확한 값인지 확인합니다.
*
* @param string strDate (예약시간)
* @return 처리결과입니다
*/
function CheckCommonTypeDate($strDate)
{
$strDate = preg_replace("/[^0-9]/", "", $strDate);
if ($strDate) {
if (!checkdate(substr($strDate, 4, 2), substr($strDate, 6, 2), substr($rsvTime, 0, 4)))
return "예약날짜오류";
if (substr($strDate, 8, 2) > 23 || substr($strDate, 10, 2) > 59) return false;
return "예약날짜오류";
}
}
+245
View File
@@ -0,0 +1,245 @@
<?php
namespace App\Libraries\slack_api;
use App\Controllers\BaseController;
use App\Libraries\slack_api\SlackChatModel;
class SlackChat extends BaseController
{
private $client, $db;
public $config;
public function __construct() {
$this->config = parse_ini_file(APPPATH.'Libraries/slack_api/config.ini', true);
$this->client = \Config\Services::curlrequest();
$this->db = new SlackChatModel();
}
public function channelList()
{
$response = $this->client->request('GET', 'https://slack.com/api/conversations.list', [
'headers' => [
"Authorization" => "Bearer {$this->config['token']}"
]
]);
$body = $response->getBody();
if (strpos($response->header('content-type'), 'application/json') !== false) {
$body = json_decode($body);
}
return $body;
}
public function channelMembers($channel)
{
$response = $this->client->request('POST', 'https://slack.com/api/conversations.members', [
'headers' => [
"Authorization" => "Bearer {$this->config['token']}",
],
'body' => "limit=1000&channel=".$this->getChannelId($channel)
]);
$body = $response->getBody();
if (strpos($response->header('content-type'), 'application/json') !== false) {
$body = json_decode($body);
}
if(isset($body->members)) $body = $body->members;
$result = $this->sendMessage(['channel'=>'U0539HPGY4U','text'=>'DM테스트']);
return $body;
}
public function channelMsgs($channel)
{
$response = $this->client->request('POST', 'https://slack.com/api/conversations.history', [
'headers' => [
"Authorization" => "Bearer {$this->config['token']}",
],
'body' => "limit=1000&channel=".$this->getChannelId($channel)
]);
$body = $response->getBody();
if (strpos($response->header('content-type'), 'application/json') !== false) {
$body = json_decode($body);
}
return $body;
}
public function getSubscriptions() {
header('Content-type: application/json');
$_POST = json_decode(file_get_contents('php://input'), true);
// $this->writeLog(file_get_contents('php://input'));
$data = [];
if(isset($_POST['challenge']))
$data['challenge'] = $_POST['challenge'];
if(isset($_POST['event']) && isset($_POST['event']['text'])) {
$key = "";
$keywords = $this->db->get_keyword();
foreach($keywords as $row) {
if(strpos($_POST['event']['text'], $row['keyword']) === false) continue;
if($row['fr_channel'] == $_POST['event']['channel']) {
$message = [
'channel' => $row['to_channel'],
'blocks' => [
[
"type" => "section",
"text" => [
"type" => "mrkdwn",
"text" => "<#{$_POST['event']['channel']}>에서 발송한 메시지 입니다."
]
],
[
"type" => "section",
"text" => [
"type" => "mrkdwn",
"text" => "<@{$_POST['event']['user']}>\n{$_POST['event']['text']}"
]
]
],
];
// $this->writeLog(json_encode($message));
$result = $this->sendMessage($message);
}
}
}
}
public function getUserInfo($user) {
$response = $this->client->request('POST', 'https://slack.com/api/users.info', [
'headers' => ["Authorization" => "Bearer {$this->config['token']}"],
'user' => $user
/*
[
'channel' => $this->getChannelId($data['channel']),
'text' => $data['text'],
'blocks' => $data['blocks']
]
*/
]);
$body = $response->getBody();
if (strpos($response->header('content-type'), 'application/json') !== false) {
$body = json_decode($body,true);
}
dd($body);
}
public function command() {
// $post = '{"token":"DJBBcWCpMQwDUc4NUvJs5uO6","team_id":"TJM4171GC","team_domain":"carelabs-kr","channel_id":"C05G82NMG8G","channel_name":"dm_botman_test","user_id":"U0539HPGY4U","user_name":"jaybe","command":"\/키워드_추가","text":"C05JESYGJH2 안녕","api_app_id":"A057ZJSCU5A","is_enterprise_install":"false","response_url":"https:\/\/hooks.slack.com\/commands\/TJM4171GC\/5648179184736\/xr6iQnJZ103MKA27PeqBRu54","trigger_id":"5624363084931.633137239556.a8dbb761125f72afec791025da822f0d"}';
// $_POST = json_decode($post,1);
// $fp = fopen(WRITEPATH.'/logs/slack_log', 'a+');
// $fw = fwrite($fp, json_encode($_POST,JSON_UNESCAPED_UNICODE).PHP_EOL);
// fclose($fp);
if(!isset($_POST['command']) && !$_POST['command']) return null;
if(!isset($_POST['text']) && !$_POST['text']) return null;
switch($_POST['command']) {
case '/키워드' : $result = $this->add_keyword($_POST); break;
case '/전송' : $result = $this->sendMsg($_POST); break;
}
echo $result;
}
private function add_keyword($data) {
preg_match_all("/^([a-z0-9]+)\s+(.+)$/i", $data['text'], $matches);
$ch_id = $matches[1][0];
$keyword = $matches[2][0];
if(!$ch_id || !$keyword) return '"/키워드_추가 [알림전송할 채널ID] [키워드]" 자세한 등록 방법은 개발팀에 문의해주세요.';
$result = [
'fr_channel' => $data['channel_id'],
'to_channel' => $ch_id,
'keyword' => $keyword,
];
$result = $this->db->add_keyword($result);
if($result) return "등록되었습니다.";
}
private function getChannelId($name) {
if(preg_match('/^[0-9a-z]+$/i', $name)) return $name;
return $this->config['ChannelID'][$name]??$this->config['UserID'][$name];
}
public function profileSet($data) {
$response = $this->client->request('POST', 'https://slack.com/api/users.profile:write', [
'headers' => ["Authorization" => "Bearer {$this->config['token']}"],
'json' => $params
/*
[
'channel' => $this->getChannelId($data['channel']),
'text' => $data['text'],
'blocks' => $data['blocks']
]
*/
]);
$body = $response->getBody();
if (strpos($response->header('content-type'), 'application/json') !== false) {
$body = json_decode($body,true);
}
}
private function sendMsg($param) {
preg_match_all("/^([^\s]+)\s+(.+)$/i", $param['text'], $matches);
$channel = $matches[1][0];
$message = $matches[2][0];
$data = [
'channel' => $channel,
'text' => $message
];
$result = $this->sendMessage($data);
if($result['ok'] == true) {
echo "전송되었습니다.";
}
}
public function sendMessage($data)
{
$params = [];
if(isset($data['channel']))
$params['channel'] = $this->getChannelId($data['channel']);
if(isset($data['text']))
$params['text'] = $data['text'];
if(isset($data['blocks']))
$params['blocks'] = $data['blocks'];
/*
[
'channel' => $this->getChannelId($data['channel']),
'text' => $data['text'],
'blocks' => $data['blocks']
]
*/
$response = $this->client->request('POST', 'https://slack.com/api/chat.postMessage', [
'headers' => ["Authorization" => "Bearer {$this->config['token']}"],
'json' => $params
]);
$body = $response->getBody();
if (strpos($response->header('content-type'), 'application/json') !== false) {
$body = json_decode($body,true);
}
if($body['ok'] == false)
$this->writeLog($body);
return $body;
}
public function sendWebHookMessage($url, $msg)
{
$data = [
"text" => $msg
];
$response = $this->client->request('POST', $url, [
'headers' => [
'Content-Type' => 'application/json',
],
'body' => json_encode($data)
]);
$body = $response->getBody();
if ($response->getStatusCode() == 200) {
$this->writeLog($body);
} else {
$this->writeLog($body);
}
}
private function writeLog($log) {
$fp = fopen(WRITEPATH.'/logs/slack_log', 'a+');
$fw = fwrite($fp, print_r($log,true).PHP_EOL);
fclose($fp);
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Libraries\slack_api;
use CodeIgniter\Model;
Class SlackChatModel extends Model {
private $zenith;
public function __construct()
{
$this->zenith = \Config\Database::connect();
}
public function get_keyword() {
$builder = $this->zenith->table('slack_keyword');
$result = $builder->get()->getResultArray();
return $result;
}
public function add_keyword($data) {
$builder = $this->zenith->table('slack_keyword');
$result = $builder->setData($data)->upsert();
return $result;
}
}