공식적인 배경 없음
백그라운드에서 PHP 스크립트를 실행하는 방법에 대한 튜토리얼에 오신 것을 환영합니다. 그래서 백그라운드에서 PHP 스크립트를 실행하는 방법을 찾고 있습니까? 어쩌면“무음 뒤에서”방대한 보고서를 위해 일부 데이터를 처리했을까요? 간단히 말해 :
그러나 우리는 어떻게 합니까? 백그라운드에서 프로세스를 어떻게 모니터링 합니까? 이 안내서에서 사용자 목록을 내보내는 예제를 통해 이 모든 내용을 살펴 보겠습니다. 계속 읽으십시오!
ⓘ이 튜토리얼의 시작 부분에 모든 소스 코드가 포함 된 zip 파일이 포함되어 있으므로 모든 것을 복사하여 붙여 넣을 필요가 없습니다.
소스 코드 다운로드
먼저 약속 한대로 소스 코드에 대한 다운로드 링크가 있습니다.
소스 코드 다운로드
소스 코드를 다운로드하려면 여기를 클릭하십시오. MIT 라이센스에 따라 릴리스되었으므로 그 위에 빌드하거나 자신의 프로젝트에서 자유롭게 사용하십시오.
빠른 시작
NOT-SO-QUICK START
DUMMY 데이터베이스 및 설정
실제 코드로 들어가기 전에 데이터베이스와 작업 할 더미 데이터 세트부터 시작하겠습니다. 모든 설정을 저장하는 작은 구성 파일과 함께.
SQL
CREATE TABLE `users` ( `user_id` int(11) NOT NULL, `user_email` varchar(255) NOT NULL, `user_name` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; INSERT INTO `users` (`user_id`, `user_email`, `user_name`) VALUES (1, 'jane@doe.com', 'Jane Doe'), (2, 'joe@doe.com', 'Joe Doe'), (3, 'john@doe.com', 'John Doe'), (4, 'julie@doe.com', 'Julie Doe'), (5, 'johan@doe.com', 'Johan Doe'), (6, 'joanne@doe.com', 'Joanne Doe'), (7, 'juliet@doe.com', 'Juliet Doe'), (8, 'june@doe.com', 'June Doe'), (9, 'juan@doe.com', 'Juan Doe'), (10, 'jamir@doe.com', 'Jamir Doe'), (11, 'jaden@doe.com', 'Jaden Doe'), (12, 'james@doe.com', 'James Doe'), (13, 'janus@doe.com', 'Janus Doe'), (14, 'jason@doe.com', 'Jason Doe'), (15, 'jay@doe.com', 'Jay Doe'), (16, 'jeff@doe.com', 'Jeff Doe'), (17, 'jenn@doe.com', 'Jenn Doe'), (18, 'joah@doe.com', 'Joah Doe'), (19, 'joyce@doe.com', 'Joyce Doe'), (20, 'joy@doe.com', 'Joy Doe'), (21, 'juke@doe.com', 'Juke Doe'), (22, 'johnnie@doe.com', 'Johnnie Doe'), (23, 'jim@doe.com', 'Jim Doe'), (24, 'jess@doe.com', 'Jess Doe'), (25, 'jabril@doe.com', 'Jabril Doe'); ALTER TABLE `users` ADD PRIMARY KEY (`user_id`), ADD UNIQUE KEY `user_email` (`user_email`), ADD KEY `user_name` (`user_name`); ALTER TABLE `users` MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=26;
테이블 필드
Field | Description |
user_id | The user ID, primary key and auto-increment. |
user_name | The user’s name. |
user_email | The user’s email. |
설정 파일
// ! CHANGE THESE TO YOUR OWN ! define('DB_HOST', 'localhost'); define('DB_NAME', 'test'); define('DB_CHARSET', 'utf8'); define('DB_USER', 'root'); define('DB_PASSWORD', ''); define('EXPORT_TO', 'd:/http/test/contacts.csv'); define('EMAIL_ADMIN', 'john@doe.com');
네, 일부 설정 만 있습니다. 이것들을 당신의 것으로 바꾸십시오.
백그라운드에서 실행
데이터베이스에는 약간의 더미 사용자 항목이 있지만 데모에는 충분합니다. 대규모 데이터베이스라고 가정하고 사용자를 백그라운드에서 CSV 파일로 내보내는 스크립트를 작성하려고 합니다.
내보내기 스크립트
// (1) INIT // Flags for process result $pass = true; $message = "OK"; require "1b-config.php"; // (2) CONNECT TO DATABASE try { $pdo = new PDO( "mysql:host=" . DB_HOST . ";charset=" . DB_CHARSET . ";dbname=" . DB_NAME, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false] ); } catch (Exception $ex) { $pass = false; $message = "Error connecting to database. ".$ex->getMessage(); } // (3) FETCH ENTRIES & GENERATE CSV FILE if ($pass) { $file = fopen(EXPORT_TO, "w"); $sql = "SELECT * FROM `users`"; $cond = null; if (isset($argv[1])) { $sql .= " WHERE `user_name` LIKE ? OR `user_email` LIKE ?"; $cond = ["%$argv[1]%", "%$argv[1]%"]; } $stmt = $pdo->prepare($sql); $stmt->execute($cond); while ($row = $stmt->fetch(PDO::FETCH_NAMED)) { fputcsv($file, [$row['user_id'], $row['user_email'], $row['user_name']]); sleep(1); } fclose($file); } // (4) EMAIL THE RESULTS WHEN COMPLETE $mailsubject = $pass ? "Process OK" : "Process ERROR" ; $mailtxt = $pass ? "Export complete - " . EXPORT_TO : $message ; @mail(EMAIL_ADMIN, $mailsubject, $mailtxt);
이 스크립트는 데이터베이스에서 사용자를 가져 와서 CSV 파일로 내 보냅니다. 꽤 간단하고 이해하기 쉬워야 합니다. 여기서 주목할 사항은 몇 가지뿐입니다.
트리거 스크립트
그게 다야 위의 스크립트는 브라우저에서 액세스하면 실제로 실행되지만 원하는 것은 아닙니다. 따라서 퍼즐의 마지막 조각을 위해 명령 행에서 내보내기를 실행할 또 다른 PHP 스크립트를 작성합니다.
<?php $cmd = "php " . __DIR__ . DIRECTORY_SEPARATOR . "2a-export.php"; // Pass in an argument if you want to search and export certain users only // $cmd = "php " . __DIR__ . DIRECTORY_SEPARATOR . "2a-export.php john"; if (strtoupper(substr(php_uname(), 0, 3)) == "WIN") { pclose(popen("start /B " . $cmd, "r")); } else { exec($cmd . " > /dev/null &"); } echo "RUNNING!"; ?>
그렇습니다. 실제로 백그라운드에서 다른 스크립트를 실행하는 데 필요한 전부입니다.
프로세스 제어
축하합니다. 이제 PHP 스크립트를 실행하는 방법을 알게 되었습니다. 그러나 더 많은 컨트롤을 원한다면 어떻게 해야 합니까? 스크립트가 중단되거나 중간에 취소하려면 어떻게 합니까? 예, 명령 행 종료 작업으로 가능하지만 먼저 시스템 프로세스 ID를 가져와야 합니다.
ⓘ 참고 – 여기 예제는 Windows 전용입니다. 그러나 이 개념은 몇 가지 조정이 가능한 Linux 기반 시스템에서 작동해야 합니다.
작업 데이터베이스 테이블
먼저, 실행 중인 모든 백그라운드 작업 및 해당 프로세스 ID를 포함 할 다른 데이터베이스 테이블을 만들어야 합니다.
CREATE TABLE `tasks` ( `user_id` int(11) NOT NULL, `process_id` varchar(12) NOT NULL, `task_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ALTER TABLE `tasks` ADD PRIMARY KEY (`user_id`), ADD KEY `task_date` (`task_date`);
Field | Description |
user_id | Primary and foreign key, the user running the task. |
process_id | System process ID. |
task_date | Time when the task is started. |
이를 통해 현재 실행 중인 작업을 추적하고 그에 따라 제한 할 수 있습니다. 사용자가 이미 백그라운드 작업을 실행 중인 경우 다른 작업을 실행할 수 없습니다.
트리거 스크립트
// (1) INIT // Dummy user id - use the user session in your own project $USERID = 999; // Flags for process result $pass = true; $result = "RUNNING!"; require "1b-config.php"; // (2) CONNECT TO DATABASE try { $pdo = new PDO( "mysql:host=" . DB_HOST . ";charset=" . DB_CHARSET . ";dbname=" . DB_NAME, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false] ); } catch (Exception $ex) { $pass = false; $message = "Error connecting to database. ".$ex->getMessage(); } // (3) CHECK IF USER ALREADY HAS RUNNING TASKS if ($pass) { $stmt = $pdo->prepare("SELECT COUNT(*) `c` FROM `tasks` WHERE `user_id`=?"); $stmt->execute([$USERID]); $count = 0; while ($row = $stmt->fetch(PDO::FETCH_NAMED)) { $count = $row['c']; } if ($count>0) { $pass = false; $result = "Already have a background task running!"; } } // (4) RUN SCRIPT IN BACKGROUND if ($pass) { // The second argument is the user ID and an option third one for search $cmd = 'wmic process call create "d:/xampp/php/php.exe -f d:/http/test/3c-export.php '. $USERID .'" | find "ProcessId"'; $handle = popen("start /B ". $cmd, "r"); $processID = preg_replace("/[^0-9]/", '', fread($handle, 200)); pclose($handle); // Create task entry in database $stmt = $pdo->prepare("INSERT INTO `tasks` (`user_id`, `process_id`) VALUES (?,?)"); $stmt->execute([$USERID, $processID]); } echo $result;
이것이 "업그레이드 된"트리거 스크립트입니다.
내보내기 스크립트
// (1) INIT // Flags for process result $pass = true; $result = "OK"; require "1b-config.php"; // (2) CONNECT TO DATABASE try { $pdo = new PDO( "mysql:host=" . DB_HOST . ";charset=" . DB_CHARSET . ";dbname=" . DB_NAME, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false] ); } catch (Exception $ex) { $pass = false; $message = "Error connecting to database. ".$ex->getMessage(); } // (3) FETCH ENTRIES & GENERATE CSV FILE if ($pass) { $file = fopen(EXPORT_TO, "w"); $sql = "SELECT * FROM `users`"; $cond = null; if (isset($argv[2])) { $sql .= " WHERE `user_name` LIKE ? OR `user_email` LIKE ?"; $cond = ["%$argv[2]%", "%$argv[2]%"]; } $stmt = $pdo->prepare($sql); $stmt->execute($cond); while ($row = $stmt->fetch(PDO::FETCH_NAMED)) { fputcsv($file, [$row['user_id'], $row['user_email'], $row['user_name']]); sleep(1); } fclose($file); } // (4) EMAIL THE RESULTS $mailsubject = $pass ? "Process OK" : "Process ERROR" ; $mailtxt = $pass ? "Export complete - " . EXPORT_TO : $message ; @mail(EMAIL_ADMIN, $mailsubject, $mailtxt); // (5) TASK COMPLETE if ($pass) { $stmt = $pdo->prepare("DELETE FROM `tasks` WHERE `user_id`=?"); $stmt->execute([$argv[1]]); }
내보내기 스크립트는 두 가지 변경 사항을 제외하고 거의 동일하게 유지됩니다.
KILL TASK SCRIPT
// (1) INIT // Dummy user id - use the user session in your own project $USERID = 999; // Flags for process result $pass = true; $result = "OK"; require "1b-config.php"; // (2) CONNECT TO DATABASE try { $pdo = new PDO( "mysql:host=" . DB_HOST . ";charset=" . DB_CHARSET . ";dbname=" . DB_NAME, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false] ); } catch (Exception $ex) { $pass = false; $message = "Error connecting to database. ".$ex->getMessage(); } // (3) FETCH RUNNING TASK $pid = 0; if ($pass) { $stmt = $pdo->prepare("SELECT * FROM `tasks` WHERE `user_id`=?"); $stmt->execute([$USERID]); while ($row = $stmt->fetch(PDO::FETCH_NAMED)) { $pid = $row['process_id']; } if ($pid==0) { $pass = false; $result = "No process running!"; } } // (4) KILL TASK if ($pass) { pclose(popen("taskkill /PID $pid /F", "r")); $stmt = $pdo->prepare("DELETE FROM `tasks` WHERE `user_id`=?"); $stmt->execute([$USERID]); } echo $result;
작업을 반쯤 취소하려면 어떻게 됩니까? 이 스크립트는 취소 마법을 수행합니다. 데이터베이스에서 프로세스 ID를 가져 와서 명령 행 태스크 종료를 실행합니다.
유용한 비트
이것으로 코드가 완성되었으며 여기에 도움이 될만한 추가 정보가 있습니다.
대안
물론, 쉘 스크립트는 병렬 처리를 수행하는 많은 방법 중 하나일 뿐입니다. 당신이 체크 아웃 할 수 있는 다른 많은 패키지가 있으며, 여기 내가 꽤 흥미로운 것으로 보이는 몇 가지가 있습니다.
링크 및 참조
등록된 댓글이 없습니다.