giftcon_dev/app/Services/SmsService.php
2026-02-07 22:51:27 +09:00

174 lines
5.7 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
class SmsService
{
private string $companyName = 'lguplus';
/**
* @param array $payload
* - from_number (필수)
* - to_number (필수)
* - message (필수)
* - subject (mms일 때 없으면 자동 생성)
* - sms_type (sms|mms) (없으면 길이로 판단)
* - country (없으면 세션/기본 82)
* - scheduled_at (옵션) : 'Y-m-d H:i' 또는 'Y-m-d H:i:s' (미래면 예약, 아니면 즉시)
*
* @param string|null $companyName
* @return bool
*/
public function send(array $payload, ?string $companyName = null): bool
{
try {
if ($companyName) {
$this->companyName = $companyName;
}
// 1) 필수값 체크 (CI의 Param_exception 대체)
if (empty($payload['from_number'])) return false;
if (empty($payload['to_number'])) return false;
if (empty($payload['message'])) return false;
// 2) country 결정 (CI sess['_mcountry_code'] 로직 대응)
$country = $payload['country'] ?? null;
if ($country === null) {
$sessCountry = Session::get('_mcountry_code'); // 기존 키 그대로 사용
if (!empty($sessCountry)) {
$country = ($sessCountry === '82' || $sessCountry === '') ? '82' : $sessCountry;
}
}
$payload['country'] = $country ?: '82';
// 3) 수신번호 체크/정리
if (!$this->phoneNumberCheck($payload)) {
return false;
}
// 4) 업체별 발송 (실제는 업체 DB insert)
return match ($this->companyName) {
'lguplus' => $this->lguplusSend($payload),
'sms2' => $this->sms2Send($payload),
default => false,
};
} catch (\Throwable $e) {
return false;
}
}
/**
* CI: phonenumber_check 로직 이식
* - country=82면 숫자만 남기고 01xxxxxxxxx 형식만 허용
*/
private function phoneNumberCheck(array &$payload): bool
{
if (($payload['country'] ?? '82') === '82') {
$num = preg_replace("/[^0-9]/", "", $payload['to_number'] ?? '');
if (preg_match("/^01[0-9]{8,9}$/", $num)) {
$payload['to_number'] = $num;
return true;
}
return false;
}
// 해외는 CI 원본처럼 그냥 통과(필요하면 국가별 검증 로직 추가)
return true;
}
/**
* ✅ 예약시간 처리(CI3 로직 그대로)
* - scheduled_at이 없으면 now()
* - 'Y-m-d H:i'면 ':00' 붙임
* - 미래면 그 시간, 과거/형식오류면 now()
*/
private function resolveProviderSendDate(?string $scheduledAt): string
{
$now = now()->format('Y-m-d H:i:s');
if (!$scheduledAt) return $now;
$scheduled = trim($scheduledAt);
// 폼은 Y-m-d H:i 로 오니 :00 붙임
if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $scheduled)) {
$scheduled .= ':00';
}
if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $scheduled)) {
if (strtotime($now) < strtotime($scheduled)) {
return $scheduled; // 미래면 예약
}
}
return $now; // 과거/형식오류면 즉시
}
/**
* CI: lguplus_send 이식
* - 메시지 길이(EUC-KR) 기준 90 이하 sms, 초과 mms
* - sms_type이 명시되면 그걸 우선
* - ✅ scheduled_at이 미래면 업체 예약 컬럼에 해당 시간으로 insert
* - SMS: SC_TRAN.TR_SENDDATE
* - MMS: MMS_MSG.REQDATE
*/
private function lguplusSend(array $data): bool
{
$conn = DB::connection('sms_server');
$smsSendType = $this->resolveSendType($data);
// ✅ 예약/즉시 결정
$sendDate = $this->resolveProviderSendDate($data['scheduled_at'] ?? null);
return (bool) $conn->transaction(function () use ($conn, $smsSendType, $data, $sendDate) {
if ($smsSendType === 'sms') {
return $conn->table('SC_TRAN')->insert([
'TR_SENDDATE' => $sendDate,
'TR_SENDSTAT' => '0',
'TR_MSGTYPE' => '0',
'TR_PHONE' => $data['to_number'],
'TR_CALLBACK' => $data['from_number'],
'TR_MSG' => $data['message'],
]);
}
$subject = $data['subject'] ?? mb_substr($data['message'], 0, 22, 'UTF-8');
return $conn->table('MMS_MSG')->insert([
'SUBJECT' => $subject,
'PHONE' => $data['to_number'],
'CALLBACK' => $data['from_number'],
'STATUS' => '0',
'REQDATE' => $sendDate,
'MSG' => $data['message'],
'FILE_CNT' => 0,
'FILE_PATH1' => '',
'TYPE' => '0',
]);
});
}
private function resolveSendType(array $data): string
{
// CI 로직과 동일한 우선순위 유지
if (!empty($data['sms_type'])) {
if ($data['sms_type'] === 'sms') {
return (mb_strlen($data['message'], 'EUC-KR') <= 90) ? 'sms' : 'mms';
}
return 'mms';
}
return (mb_strlen($data['message'], 'EUC-KR') <= 90) ? 'sms' : 'mms';
}
private function sms2Send(array $data): bool
{
// TODO: 업체 연동 시 구현
return true;
}
}