댓글 검색 목록

[php] 백그라운드에서 PHP 스크립트를 실행하는 방법

페이지 정보

작성자 운영자 작성일 20-04-17 11:42 조회 1,274 댓글 0

공식적인 배경 없음 


백그라운드에서 PHP 스크립트를 실행하는 방법에 대한 튜토리얼에 오신 것을 환영합니다. 그래서 백그라운드에서 PHP 스크립트를 실행하는 방법을 찾고 있습니까? 어쩌면“무음 뒤에서”방대한 보고서를 위해 일부 데이터를 처리했을까요? 간단히 말해 :

  • 먼저 평소와 같이 PHP 스크립트를 작성해야 합니다.
  • 그런 다음 exec 또는 popen 함수를 사용하여 명령 행에서 스크립트를 실행하십시오.

그러나 우리는 어떻게 합니까? 백그라운드에서 프로세스를 어떻게 모니터링 합니까? 이 안내서에서 사용자 목록을 내보내는 예제를 통해 이 모든 내용을 살펴 보겠습니다. 계속 읽으십시오!

ⓘ이 튜토리얼의 시작 부분에 모든 소스 코드가 포함 된 zip 파일이 포함되어 있으므로 모든 것을 복사하여 붙여 넣을 필요가 없습니다.


소스 코드 다운로드 


먼저 약속 한대로 소스 코드에 대한 다운로드 링크가 있습니다.


소스 코드 다운로드 


소스 코드를 다운로드하려면 여기를 클릭하십시오. MIT 라이센스에 따라 릴리스되었으므로 그 위에 빌드하거나 자신의 프로젝트에서 자유롭게 사용하십시오.


빠른 시작 


  • 폴더에 다운로드하여 압축을 풉니다.
  • 데이터베이스를 작성하고 1a-users.sql을 가져 오십시오.
  • 1b-config.php의 데이터베이스, 내보내기 및 이메일 설정을 원하는 대로 변경하십시오.
  • 브라우저에서 2b-run.php를 실행하십시오 – 백그라운드에서 명령 행에 2a-export.php가 실행됩니다.

NOT-SO-QUICK START 


  • 백그라운드 프로세스 (취소 또는 제한)에 대한 더 많은 제어를 원하는 사람에게는 3a-tasks.sql도 가져옵니다. 2a 및 2b는 거의 무시할 수 있습니다.
  • 3b-run.php 편집 39 행에서 명령에 대한 경로가 올바른지 확인하십시오 – $ cmd = 'wmic process call create "d : /xampp/php/php.exe -fd : / http / test / 3c-export .php '. $ USERID.' "| "ProcessId"를 찾으십시오. ';
  • 대신 3b-run.php를 시작하십시오.


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; 


테이블 필드 


FieldDescription
user_idThe user ID, primary key and auto-increment.
user_nameThe user’s name.
user_emailThe user’s email.

설정 파일 


<?php // ! 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 파일로 내보내는 스크립트를 작성하려고 합니다.


내보내기 스크립트 


<?php // (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!"; ?> 


그렇습니다. 실제로 백그라운드에서 다른 스크립트를 실행하는 데 필요한 전부입니다.

  • Unix 기반 Mac OSX 및 Linux의 경우 exec()를 사용하여 백그라운드 터미널에서 스크립트를 실행합니다.
  • exec()는 우리가 원하지 않는 스크립트가 끝날 때까지 기다립니다. 따라서 popen()으로 쉘 스크립트를 실행하고 pclose()로 핸들러를 즉시 닫아야 합니다.


프로세스 제어 


축하합니다. 이제 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`); 


FieldDescription
user_idPrimary and foreign key, the user running the task.
process_idSystem process ID.
task_dateTime when the task is started.

이를 통해 현재 실행 중인 작업을 추적하고 그에 따라 제한 할 수 있습니다. 사용자가 이미 백그라운드 작업을 실행 중인 경우 다른 작업을 실행할 수 없습니다.


트리거 스크립트 


<?php // (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; ?> 


이것이 "업그레이드 된"트리거 스크립트입니다.


  • 내보내기 스크립트를 실행하기 전에 백그라운드에서 다른 스크립트가 이미 실행 중인지 확인합니다.
  • 해당 특정 사용자에 대해 실행 중인 다른 백그라운드 작업이 없는 경우에만 계속 진행됩니다.
  • 여기에 평소보다 조금 더 많은 명령 줄 요가가 있습니다. 기본적으로 "wmic"로 새 작업을 만들고 시스템 프로세스 ID를 가져옵니다.
  • 그런 다음 스크립트가 계속 실행될 때 프로세스 ID를 데이터베이스에 저장합니다.
  • 사용자 ID를 내보내기 스크립트로 전달해야 합니다.

내보내기 스크립트 


<?php // (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]]); } ?> 


내보내기 스크립트는 두 가지 변경 사항을 제외하고 거의 동일하게 유지됩니다.

  • 먼저, 명령 행에서 사용자 ID를 전달해야 합니다.
  • 작업이 완료되면 태스크 데이터베이스 항목을 삭제하십시오.

KILL TASK SCRIPT 


<?php // (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를 가져 와서 명령 행 태스크 종료를 실행합니다.


유용한 비트 


이것으로 코드가 완성되었으며 여기에 도움이 될만한 추가 정보가 있습니다.


대안 


물론, 쉘 스크립트는 병렬 처리를 수행하는 많은 방법 중 하나일 뿐입니다. 당신이 체크 아웃 할 수 있는 다른 많은 패키지가 있으며, 여기 내가 꽤 흥미로운 것으로 보이는 몇 가지가 있습니다.

링크 및 참조 




댓글목록 0

등록된 댓글이 없습니다.

웹학교 로고

온라인 코딩학교

코리아뉴스 2001 - , All right reserved.