Rocky Linux 9.x, PHP 8.1.x 환경에서 Laravel 10.33.0 설치하기
내용을 보시려면 비밀번호를 입력하세요.
[php] PHPMailer 로 외부 SMTP 활용하여 메일 보내기 (0) | 2024.02.08 |
---|---|
Rocky Linux 9.x, PHP 8.1.x 환경에서 Laravel 10.33.0 설치하기 (0) | 2023.11.23 |
PHP 소켓 (server.php, client.php) - 데이터 전달 예제 (0) | 2023.07.07 |
PHP 에서 SQL Injection 방지 쿼리 사용법 두가지 (bind_param, PDO) (0) | 2022.08.30 |
PHP 날짜 비교하기 (0) | 2022.04.13 |
움직이는 GIF 파일과 같이 움직이는 PNG 파일인 APNG 입니다.
GIF 보다 용량도 작고 고화질로 출력이 가능해 안드로이드의 아이콘이나 버튼으로 사용하기 좋습니다.
라이브러리 : https://github.com/penfeizhou/APNG4Android
1. 준비
build.gradle 파일에 dependency 를 추가합니다.
... repositories { mavenCentral() } ... APNG dependencies { implementation 'com.github.penfeizhou.android.animation:apng:${VERSION}' } ... |
2. 사용
APNG 파일 (예: sysdocu.png) 은 assets 폴더에 저장합니다.
... // asset 파일에서 불러오기 AssetStreamLoader assetLoader = new AssetStreamLoader(context, "sysdocu.png"); // APNG Drawable 생성 APNGDrawable apngDrawable = new APNGDrawable(assetLoader); // 자동 실행 imageView.setImageDrawable(apngDrawable); ... |
안드로이드 java 에서 웹페이지 출력 내용을 String 에 넣기 (0) | 2024.11.30 |
---|---|
AndroidStudio 에서 JAVA 로 GPS 현재 위치 확인하기 (0) | 2024.11.01 |
FCM 을 활용한 PUSH 메세지 보내기 (2024-11-23) (0) | 2022.10.19 |
안드로이드 알람 생성 2가지 방법 (Android Notifications Tutorial with Examples) (0) | 2022.07.18 |
안드로이드 비정상 종료 감지 처리 (어플 재시작) (0) | 2021.06.08 |
PHP 를 이용해 Server 에서 소켓 파일을 만들어 실행한 상태에서 Client 가 데이터를 전달하는 예제입니다.
데이터 (Mac address) 를 보내면 Server 측에서 데이터 검증 후 출력하도록 작성하였습니다.
받은 데이터 로그는 /root/input_data.log 에 기록 됩니다.
# vi server.php
#!/usr/bin/php -q <?php set_time_limit(0); define("_IP", "0.0.0.0"); define("_PORT", "80"); $sSock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option($sSock, SOL_SOCKET, SO_REUSEADDR, 1); socket_bind($sSock, _IP, _PORT); socket_listen($sSock); pcntl_signal(SIGCHLD, SIG_IGN); function msg($msg) { echo "SERVER >> ".$msg; } // 맥어드레스 형식 검증 function isMacAddress($str) { $pattern = '/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/'; return preg_match($pattern, $str); } while($sock = socket_accept($sSock)) { socket_getpeername($sock, $sockIp, $sockPort); msg("Client connect : ".$sockIp.":".$sockPort."\n"); // 자식 프로세스 생성 $pid = pcntl_fork(); if($pid == -1) { msg("fork failed\n"); exit; } if($pid == 0) { $input = socket_read($sock, 4096); // 헤더와 데이터 분리 list($header, $data) = explode("\r\n\r\n", $input, 2); msg("Mac address : " . $data . "\n"); // 결과 응답 및 Client 연결 해제 if ($input != "") { socket_write($sock, "Received it well"); msg("Client disconnect : ".$sockIp.":".$sockPort."\n"); socket_close($sock); } // 데이터 검증 if (isMacAddress($data)) { $validation = "OK"; } else { $validation = "NotOK"; } // 로그 기록 $now = date("Y-m-d H:i:s"); shell_exec("echo \"$now\" \"$data\" \"$validation\" >> /root/input_data.log"); exit; } } ?> |
맨 윗줄 #!/usr/bin/php -q 에는 실제 php 실행파일 경로를 적어줘야 합니다.
root 만 사용할 수 있도록 권한을 변경합니다.
# chmod 700 server.php
파일을 실행하여 80 포트를 오픈하고 client 의 수신을 대기합니다.
# php server.php
Client 파일을 만듭니다.
# vi client.php
<?php $url = 'http://www.sysdocu.kr'; // 접속할 호스트명 $data = '00:d8:61:13:2a:b8'; // 전달하고 싶은 데이터 (여기에서는 Mac address) $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_exec($ch); curl_close($ch); ?> |
Server 측 소켓이 열린 상태에서 client.php 파일을 실행하면 미리 준비된 데이터가 전달 됩니다.
# php client.php
Rocky Linux 9.x, PHP 8.1.x 환경에서 Laravel 10.33.0 설치하기 (0) | 2023.11.23 |
---|---|
PHP 코드를 실행해주는 사이트 (버전 선택 가능) (0) | 2023.11.17 |
PHP 에서 SQL Injection 방지 쿼리 사용법 두가지 (bind_param, PDO) (0) | 2022.08.30 |
PHP 날짜 비교하기 (0) | 2022.04.13 |
[PHP] AES-256-CBC 를 이용한 암호화 및 복호화 (0) | 2022.04.11 |
C/C++의 콘솔 환경에서 프로그레스바 (진행바) 구현 소스입니다.
아래와 같이 심플하게 개수, 프로그레스바, 진행률 이 출력됩니다.
10/10 [==================================================] 100%
#include <stdio.h> #include <stdlib.h> #include <windows.h> // Sleep 함수 int main() { const char bar = '='; // 프로그레스바 문자 const char blank = ' '; // 비어있는 프로그레스바 문자 const int LEN = 20; // 프로그레스바 길이 const int MAX = 1000; // 진행작업 최대값 const int SPEED = 50; // 카운트 증가 대기시간 int count = 0; // 현재 진행된 작업 int i; // 반복문 전용 변수 float tick = (float)100/LEN; // 몇 %마다 프로그레스바 추가할지 계산 printf("%0.2f%% 마다 bar 1개 출력\n\n", tick); int bar_count; // 프로그레스바 갯수 저장 변수 float percent; // 퍼센트 저장 변수 while(count <= MAX) { printf("\r%d/%d [", count, MAX); // 진행 상태 출력 percent = (float)count/MAX*100; // 퍼센트 계산 bar_count = percent/tick; // 프로그레스바 갯수 계산 for(i=0; i<LEN; i++) { // LEN길이의 프로그레스바 출력 if(bar_count > i) { // 프로그레스바 길이보다 i가 작으면 printf("%c", bar); } else { // i가 더 커지면 printf("%c", blank); } } printf("] %0.2f%%", percent); // 퍼센트 출력 count++; // 카운트 1증가 Sleep(SPEED); // SPEEDms 대기 } printf(" done!\n\n"); system("pause"); // 프로그램 종료 전 일시정지 return 0; } |
1000개의 전체 작업량 중 1개가 완료되었다면 진행률은 0.1%가 됩니다.
현재 진행량/전체 진행량 * 100 = 진행률(%)
100분율 계산법입니다.
해당 연산은 코드의 19행에서 진행하고 있습니다.
현재 진행량은 코드상에서 count 변수
전체 진행향은 코드상에서 MAX 변수입니다.
진행률을 계산했으면 해당 진행률을 기준으로 프로그레스바(진행바)를 출력해야합니다.
100(%)/프로그레스바 길이 = 몇 %마다 프로그레스바 1개 출력
만약 프로그레스바의 길이가 20이라고 하면
100/20 = 5
[====================] 100%
위의 모습일겁니다.
길이는 고정되어있음으로 진행률 퍼센트에 따라 = 문자를 출력해줘야 하죠
코드의 13행에서 해당 계산을 진행하고 있습니다.
계산 후 tick 이라는 변수에 저장해두었습니다.
20길이의 프로그레스바는 5% 마다 = 한개를 출력합니다.
10%라고 하면 == 를 출력하겠죠?
17~31행의 while 문은 0~전체 진행량까지 반복하는 반복문입니다.
19행에서 매번 반복마다 진행률(%)을 계산하여
20행에서 프로그레스바 = 문자를 몇개 출력할지 계산한 후
그 아래 21행 for문에서 출력을 합니다.
for문은 0~LEN 까지 반복을 하는데 LEN은 프로그레스바의 길이가 저장되있는 변수이름입니다.
20이라고 가정하면 0~20까지 반복하계되죠
bar_count는 20행에서 현재 %는 몇개의 =문자를 출력할지 저장되어있습니다.
만약 프로그레스바 길이가 20이고 진행률이 7%라고 가정합시다.
1 - 13행처럼 먼저 몇 %마다 =문자를 출력할지 계산
100/20 = 5(%)
tick = 5
2 - bar_count에 현재 퍼센트는 몇개의 =를 출력할지 계산
percent/tick = 갯수
7/5 = 1(나머지 버림)
bar_count = 1
3 - for문에서 출력
LEN이 20이므로 i = 0~20
if(bar_count > i)
0~20까지 i가 증가하면서 bar_count와 비교하여 출력
bar_count는 현재 1이 저장되어있으므로 i가 0일때만 참
20번 반복하면서 =하나를 출력하게 되고
거짓인 경우에는 else 로 가서 공백을 출력합니다.
4 - for문으로 출력 후 퍼센트 출력 및 count 증가
count(현재 진행량)를 1 증가
위의 과정을 현재 진행량~전체 진행량까지 반복하여 100%가 되면 종료합니다.
출력하는데 왜 이어서 출력이 되지않고 원래 위치 그대로에서 출력될까요?
그 문제는 18행에 있습니다.
printf("\r")
\r 이스케이프 시퀀스는 해당 라인의 첫 번째 위치로 이동합니다.
첫 번째로 이동한 후 다시 출력을 하게되어 위치가 바뀌지않고 진행되는이유입니다.
[C] 자신과 동일한 프로세스 이름이 가동중인지 확인하는 코드 (중복 실행 차단) (0) | 2024.08.27 |
---|---|
[C++] 파일쓰기 예제 (0) | 2023.12.11 |
[C/C++] int 를 char 또는 const char* 로 변환하기 (0) | 2022.06.30 |
C++ 프로그램 중복 실행 방지 (윈도우 기반) (0) | 2021.05.18 |
C++ 에서 구동 파일의 절대 경로 확인하기 (windows) (0) | 2021.05.17 |
시스템 운영을하며 많이 접하는 명령이 grep 이기도 한데 구체적인 문자열 검색을 위해 정규표현식이 사용됩니다.
어떤 행에서 '몇개의 숫자, 점, 몇개의 숫자' 로 이루어진 문자열은 아래와 같이 출력합니다.
grep '[0-9]*[.][0-9]*'
[Shell Script] 텍스트 좌우 정렬, 가운데 공백 채우기 (0) | 2024.07.05 |
---|---|
[ShellScript] 로그 파일 실시간 감시 및 마지막행 처리 방법 (0) | 2023.03.29 |
[쉘스크립트] 오래된 백업 파일 삭제하기 (0) | 2023.01.13 |
쉘스크립트 rsync 실행시 끝에 \#015 문자가 붙는 경우 조치방법 (0) | 2023.01.11 |
[Shell Script] MySQL 테이블 별로 백업 하기 (0) | 2022.09.08 |
쉘스크립트 파일을 아래 내용으로 작성하고 실행하면 됩니다.
# vi monitor_and_run.sh
#!/bin/bash FILE="/home/sysdocu/app.log" # 감시할 파일명 # 파일 감시 및 처리 tail -F -n 0 "$FILE" |\ while read line do # 로그에서 특정 문자열 확인 및 처리 case "$line" in *"test"*) # 여기에 일치되는 문자열 echo 마지막으로 추가된 행 내용 : $line ;; esac done |
* 결과
마지막으로 추가된 행 내용 : 이건 test 입니다.
마지막으로 추가된 행 내용 : lasttest
마지막으로 추가된 행 내용 : test
마지막으로 추가된 행 내용 : test 끝
[Shell Script] 텍스트 좌우 정렬, 가운데 공백 채우기 (0) | 2024.07.05 |
---|---|
정규표현식 연속된 문자 검색 (0) | 2023.06.02 |
[쉘스크립트] 오래된 백업 파일 삭제하기 (0) | 2023.01.13 |
쉘스크립트 rsync 실행시 끝에 \#015 문자가 붙는 경우 조치방법 (0) | 2023.01.11 |
[Shell Script] MySQL 테이블 별로 백업 하기 (0) | 2022.09.08 |
백업스크립트로 데이터를 백업할때 디스크용량이 꽉 차는것을 방지하기 위해 보통은 스크립트 상단에 오래된 백업 파일 또는 디렉토리를 삭제하도록 합니다.
하지만 오래된 디렉토리를 삭제할 경우 그 안의 내용은 지워지지만 디렉토리 자체는 날짜가 갱신되어 (Access, Modify, Change) 삭제가 되지 않습니다.
이 경우 아래와 같이 조치가 가능합니다.
예) 20 으로 시작되는 날짜 디렉토리 중 30일이 초과된 디렉토리 삭제
1) 기존 방법
명령 : find /backup/20* -ctime +30 -exec rm -rf {} \;
결과 : 날짜가 오래된 디렉토리 내 파일은 삭제되지만 디렉토리는 남게됩니다.
2) 새 방법
디렉토리의 변경되지 않는 Birth 날짜와 현재 날짜를 비교하여 삭제
cd /backup LIST=`stat -c %n" "%w 20* |sed -e 's/-//g' |awk {'print $1" "$2'}` while read i j; do # i : Directory name, j : Birth date if [ $j -le `date +%Y%m%d --date '30 days ago'` ]; then rm -rf $i fi; done <<< "$LIST" |
* 참고
파일 또는 디렉토리의 날짜 확인
# stat 20230102
File: 20230102
Size: 30 Blocks: 0 IO Block: 4096 디렉토리
Device: 821h/2081d Inode: 1799764911 Links: 4
Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2023-01-11 12:00:01.478938107 +0900
Modify: 2023-01-02 12:00:02.236334564 +0900
Change: 2023-01-02 12:00:02.236334564 +0900
Birth: 2023-01-02 00:00:01.354856557 +0900
정규표현식 연속된 문자 검색 (0) | 2023.06.02 |
---|---|
[ShellScript] 로그 파일 실시간 감시 및 마지막행 처리 방법 (0) | 2023.03.29 |
쉘스크립트 rsync 실행시 끝에 \#015 문자가 붙는 경우 조치방법 (0) | 2023.01.11 |
[Shell Script] MySQL 테이블 별로 백업 하기 (0) | 2022.09.08 |
쉘스크립트 수 비교하기 (0) | 2021.06.10 |
파일 리스트 등의 결과를 변수에 넣고 rsync 로 한줄씩 사용하고자 할때 아래와 같은 현상이 발생되었습니다.
이밖에 다른 경우에도 같은 현상이 나타날 수 있는데, 이때 해결방법은 아래와 같습니다.
방법1)
리스트가 list.txt 에 있는 경우 개행문자를 제거하고
list_new.txt 라는 새로운 파일에 입력합니다.
# tr -d '\r' < list.txt > list_new.txt
방법2)
sed -i 's/^M//' list.txt
여기에서 ^M 은 ctrl 키를 누른 상태에서 v, m 을 순서대로 누르는 것입니다.
(ctrl + v + m)
[ShellScript] 로그 파일 실시간 감시 및 마지막행 처리 방법 (0) | 2023.03.29 |
---|---|
[쉘스크립트] 오래된 백업 파일 삭제하기 (0) | 2023.01.13 |
[Shell Script] MySQL 테이블 별로 백업 하기 (0) | 2022.09.08 |
쉘스크립트 수 비교하기 (0) | 2021.06.10 |
파일과 현재시간의 timestamp 구하기, 차이 계산하기 (0) | 2021.03.26 |
New Project > Empty Views Activity 선택
Language : Java
Minimum SDK : API 24
이 상태로 진행하였습니다.
build.gradle 수정 (프로젝트 수준)
아래 내용을 파일에 추가 합니다.
... buildscript { dependencies { classpath("com.google.gms:google-services:4.4.2") } } |
build.gradle 수정 (앱 수준)
아래 내용을 추가 합니다.
중간에 주석 부분도 추가해줍니다. 없을 경우 바로 아랫줄에 구문 에러 메세지가 출력됩니다.
plugins { alias(libs.plugins.android.application) id("com.google.gms.google-services") } ... dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:2.0.4' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation(platform("com.google.firebase:firebase-bom:33.6.0")) implementation("com.google.firebase:firebase-analytics") implementation("com.google.firebase:firebase-messaging:24.1.0") implementation("com.google.firebase:firebase-core:21.1.1") } |
google-services.json 생성
Firebase console 페이지에 접근해서 프로젝트에 APP 을 추가합니다.
추가하는 과정에서 google-services.json 파일을 다운로드 받을 수 있으며,
해당 파일은 app 디렉토리 안에 넣어 놓습니다.
build.gradle 페이지에서 [Sync Now] 버튼을 눌러줍니다.
MyFirebaseMessagingService.java 생성
package kr.sysdocu.fcm; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; public class MyFirebaseMessagingService extends FirebaseMessagingService { @Override public void onNewToken(@NonNull String token) { super.onNewToken(token); // token을 서버로 전송해서 저장하고 싶은 경우 이곳에 코드 입력 } @Override public void onMessageReceived(@NonNull RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); String messageContent; // 푸시 메시지 데이터 처리 if (!remoteMessage.getData().isEmpty()) { // Data Payload 처리 messageContent = remoteMessage.getData().get("message"); String title = remoteMessage.getData().get("title"); showNotification(title, messageContent); // 아래에서 정의한 알람을 실행하는 부분 } else if (remoteMessage.getNotification() != null) { // Notification Payload 처리 messageContent = remoteMessage.getNotification().getBody(); } else { messageContent = "No Content"; } } // 알람을 띄운다 private void showNotification(String title, String message) { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); String channelId = "default_channel_id"; // Android 8.0 (API 26) 이상에서는 알림 채널을 생성해야 함 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( channelId, "Default Channel", NotificationManager.IMPORTANCE_DEFAULT ); notificationManager.createNotificationChannel(channel); } // 알림 클릭 시 실행할 Intent 정의 Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 기존 Activity 스택 제거 후 실행 // PendingIntent 생성 PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE // 최신 상태 유지 ); // 알림 빌더 구성 NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId) .setContentTitle(title) // 알림 제목 .setContentText(message) // 알림 메시지 .setSmallIcon(R.drawable.ic_icon) // 알림 아이콘 .setAutoCancel(true) // 알림 터치 후 제거 .setContentIntent(pendingIntent); // 알림 클릭 시 실행될 PendingIntent 설정 // 알림 표시 notificationManager.notify(0, notificationBuilder.build()); } } |
MainActivity.java 수정
여기에서 코드를 작성할때 파란색 부분은 okhttp 라이브러리를 이용해 토큰을 웹서버로 전송하기 위한 부분입니다.
필요시 같이 작성하면 됩니다.
앱수준 build.gradle 파일에 dependencies 추가후 sync 맞추기
implementation("com.squareup.okhttp3:okhttp:4.11.0")
package kr.sysdocu.fcm; import android.os.Bundle; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.google.android.gms.tasks.OnSuccessListener; import com.google.firebase.messaging.FirebaseMessaging; public class MainActivity extends AppCompatActivity { private final OkHttpClient client = new OkHttpClient(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 이 안의 부분은 처음 토큰을 받아올때 한 번만 실행 됩니다. FirebaseMessaging.getInstance().getToken().addOnSuccessListener(new OnSuccessListener<String>() { @Override public void onSuccess(String token) { // 토큰을 토스트로 간단히 확인 Toast toast = Toast.makeText(getApplicationContext(), "TOKEN : " + token, Toast.LENGTH_LONG); toast.show(); // 서버로 토큰 전송 (ssl 사용) new Thread(() -> { try { String url = "https://fcm.sysdocu.kr/register.html?token=" + token; String result = run(url); // 결과 처리 (예: 로그 출력) System.out.println(result); } catch (IOException e) { e.printStackTrace(); } }).start(); } }); } // okhttp 라이브러리 사용 // run 메서드는 클래스 수준에 정의해야 합니다. public String run(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } } |
activity_main.xml 수정
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:background="#DFE5E5" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="@color/black" android:text="토큰은 웹서버에서 확인하세요." /> </LinearLayout> |
AndroidManifest.xml
아래 내용을 추가합니다.
(생략) <uses-permission android:name="android.permission.INTERNET"/> ... // <application> 안에 아래 내용 추가 <service android:name=".MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT"/> </intent-filter> </service> (생략) |
프로젝트를 빌드하여 apk 파일을 생성하고, 핸드폰에 설치합니다.
잠깐, 앱을 실행하기 전에 아래 내용 확인해주세요.
위 소스에서 사용되었던 서버 URL (https://fcm.sysdocu.kr/register.html) 에 해당되는 파일을 미리 생성해 놓도록 합니다.
access log 에 접근 로그가 남아 token 확인을 쉽게하기 위함이니 빈 파일도 괜찮습니다.
PUSH 발송 테스트
방법1)
Firebase Console 에서 프로젝트 선택 > '실행' 메뉴 > 'Messaging' 메뉴 > (첫 번째 캠페인 만들기) 버튼 클릭 > Firebase 알림 메세지 체크 후 [만들기]
출력된 화면에서 적절한 내용으로 모두 입력 후 [검토] 버튼을 누르면, 앱을 설치한 모든 Device 로 FCM 메세지가 발송 됩니다.
방법2)
PHP 코드를 아래와 같이 작성 합니다.
현재 (2024년 11월) 는 이전에 사용하던 방식에서 FCM HTTP API의 v1 버전으로 전송 방식이 바뀌었습니다.
1) 사용자 계정 키 (json) 다운로드
서비스 계정 키 다운로드를 위해 Firebase Console (https://console.firebase.google.com/ ) 로 이동합니다.
프로젝트 설정 > 서비스 계정 > 새 비공개 키 생성 클릭.
JSON 파일을 다운로드합니다.
다운로드 한 파일은 PHP 생성할 위치로 복사합니다.
2) php 파일 작성
v1 API 는 OAuth2 인증을 사용해야 하므로 google/apiclient 패키지를 설치합니다.
# composer require google/apiclient
아래 파란색 부분을 적절한 값으로 수정하여 작성합니다.
# vi fcm_send.php
<?php require 'vendor/autoload.php'; use Google\Auth\Credentials\ServiceAccountCredentials; use GuzzleHttp\Client; function sendFCMMessage($serviceAccountPath, $projectId, $token, $title, $body) { // FCM 엔드포인트 URL $url = "https://fcm.googleapis.com/v1/projects/$projectId/messages:send"; // 메시지 페이로드 $message = [ 'message' => [ 'token' => $token, 'data' => [ 'title' => $title, 'message' => $body ] ] ]; // Google OAuth2 인증 $credentials = new ServiceAccountCredentials( 'https://www.googleapis.com/auth/firebase.messaging', json_decode(file_get_contents($serviceAccountPath), true) ); $accessToken = $credentials->fetchAuthToken()['access_token']; // HTTP 요청 헤더 $headers = [ 'Authorization' => 'Bearer ' . $accessToken, 'Content-Type' => 'application/json', ]; // HTTP 클라이언트 $client = new Client(); try { // FCM 메시지 요청 $response = $client->post($url, [ 'headers' => $headers, 'body' => json_encode($message) ]); echo "Response: " . $response->getBody(); } catch (Exception $e) { echo "Error: " . $e->getMessage(); } } // 서비스 계정 JSON 파일 경로 $serviceAccountPath = './your-service-account.json'; // Firebase 프로젝트 ID $projectId = 'your-project-id'; // FCM 토큰, 제목, 내용 $token = 'your-device-token'; $title = 'Test Title'; $body = 'Test Body'; // 메시지 전송 함수 호출 sendFCMMessage($serviceAccountPath, $projectId, $token, $title, $body); ?> |
이제 작성한 파일을 실행만 하면 입력해놓은 특정 디바이스로 (token) FCM 메세지가 전송됩니다.
# php fcm_send.php
AndroidStudio 에서 JAVA 로 GPS 현재 위치 확인하기 (0) | 2024.11.01 |
---|---|
[Android] APNG 사용하기 (0) | 2023.08.24 |
안드로이드 알람 생성 2가지 방법 (Android Notifications Tutorial with Examples) (0) | 2022.07.18 |
안드로이드 비정상 종료 감지 처리 (어플 재시작) (0) | 2021.06.08 |
안드로이드 와이파이 SSID 가져오기 (0) | 2021.06.02 |
쉘스크립트를 이용하여 모든 데이터베이스를 테이블 별로 백업하는 방법 입니다.
파일명은 {DB명}.{테이블명}.sql 형식으로 남게 됩니다.
# vi mysql_backup_by_table.sh
#!/bin/bash today=`date +%Y%m%d` # 백업 디렉토리 mkdir -p /backup/${today} cd /backup/${today} # MySQL root 패스워드 root_pw='12345678' # 1) 모든 DB 백업 list=`echo "show databases;" |mysql -uroot -p"$root_pw"` # 2) 선택한 DB 만 백업 (개행 \n 으로 구분) #list=`echo -e "mysql\nmonitor\nsysdocu"` for db in $list; do table_list=`echo "show tables" |mysql -uroot -p"$root_pw" $db` for table in $table_list; do mysqldump -uroot -p"$root_pw" $db $table > ${db}.${table}.sql #tar cvzf ${db}.${table}.tar.gz ${db}.${table}.sql --remove-files # 압축 보관 및 원본 삭제 done done |
# chmod 700 mysql_backup_by_table.sh
실행
# sh mysql_backup_by_table.sh
[쉘스크립트] 오래된 백업 파일 삭제하기 (0) | 2023.01.13 |
---|---|
쉘스크립트 rsync 실행시 끝에 \#015 문자가 붙는 경우 조치방법 (0) | 2023.01.11 |
쉘스크립트 수 비교하기 (0) | 2021.06.10 |
파일과 현재시간의 timestamp 구하기, 차이 계산하기 (0) | 2021.03.26 |
쉘스크립트에서 특정시간의 전 후 시간 계산 하기 (0) | 2020.11.04 |