2013-05-13 27 views
7

Vấn đề là trong một quá trình dài, tập lệnh PHP tiếp tục thực hiện cho dù trình duyệt của khách hàng hiện có được kết nối hay không. Có khả năng rằng nếu khách hàng đã chấm dứt cuộc gọi Ajax đến một kịch bản thì kịch bản cũng chấm dứt trên máy chủ?PHP tự động giết một tập lệnh nếu yêu cầu HTTP bị hủy/đóng

+0

Trong số những khó khăn là một cuộc gọi ajax mới sẽ phải được thực hiện cho các máy chủ, trong đó bao gồm một kịch bản PHP thứ hai chạy. Kịch bản lệnh PHP thứ hai đó sẽ cần phải có quyền truy cập vào luồng được tạo bởi tập lệnh PHP đầu tiên. Tôi có thể nghĩ ra một số cách để làm điều này - nhưng nó sẽ không tự động. Bạn cần phải chắc chắn mã PHP của bạn để làm cho các chủ đề ban đầu có thể truy cập hoặc kiểm soát một cách nào đó bởi một chủ đề mới và độc lập tạo ra. –

+0

Thực ra hành vi mặc định của PHP là hủy bỏ quá trình nếu máy khách ngắt kết nối. – Jon

+0

@jon Trong tình huống của tôi trên máy chủ cửa sổ, nó tiếp tục chạy sau khi ngắt kết nối. Tuy nhiên tôi cũng không muốn PHP chỉ đóng quá trình. Tôi cần phải ROLLBACK db giao dịch và tắt máy một cách an toàn. –

Trả lời

8

Như được chỉ ra bởi @metadings php không có chức năng kiểm tra kết nối hủy có tên connection_aborted(). Nó sẽ trở lại 1 nếu kết nối được chấm dứt bằng cách khác 0.

Trong một quá trình phía máy chủ lâu người sử dụng có thể cần phải biết nếu khách hàng bị ngắt kết nối từ máy chủ hoặc ông đã đóng trình duyệt sau đó máy chủ thể một cách an toàn tắt quá trình.

Đặc biệt trong trường hợp ứng dụng sử dụng phiên php sau đó nếu chúng tôi rời quá trình chạy ngay cả sau khi máy khách bị ngắt kết nối thì máy chủ sẽ không phản hồi cho phiên này. Và bất kỳ yêu cầu nào khác từ cùng một máy khách sẽ đợi cho đến khi quá trình trước đó thực thi hoàn toàn. Lý do cho tình huống này là tệp phiên bị khóa khi quá trình đang chạy. Tuy nhiên, bạn có thể gọi phương thức session_write_close() để mở khóa nó. Nhưng điều này là không khả thi trong tất cả các kịch bản, có thể là một trong những cần phải viết một cái gì đó để phiên vào cuối của quá trình.

Bây giờ nếu chúng tôi chỉ gọi connection_aborted() trong vòng lặp thì nó sẽ luôn luôn trả lại 0 cho dù kết nối có được đóng hay không.

0 có nghĩa là kết nối không bị hủy. Nó là sai lầm.Tuy nhiên, sau khi tìm kiếm lại và thử nghiệm nếu phát hiện ra rằng bộ đệm đầu ra đầu ra là trong php là lý do.

Trước hết để kiểm tra việc hủy bỏ nhà phát triển trong một vòng lặp phải gửi một số đầu ra cho khách hàng bằng cách lặp lại một số văn bản. Ví dụ:

print " "; 

Khi quá trình vẫn chạy, đầu ra sẽ không được gửi cho khách hàng. Bây giờ để gửi đầu ra, sau đó chúng ta cần xóa bộ đệm đầu ra.

flush(); 
ob_flush(); 

Và sau đó nếu chúng tôi kiểm tra hủy bỏ thì nó sẽ cho kết quả chính xác.

if (connection_aborted() != 0) { 
    die(); 
} 

Sau đây là ví dụ làm việc, điều này sẽ làm việc ngay cả khi bạn đang sử dụng phiên PHP:

session_start(); 
ignore_user_abort (TRUE); 

file_put_contents ("con-status.txt", "Process started..\n\n"); 

for($i = 1; $i <= 15; $i ++) { 

    print " "; 

    file_put_contents ("con-status.txt", "Running process unit $i \n", FILE_APPEND); 
    sleep (1); 

    // Send output to client 
    flush(); 
    ob_flush(); 

    // Check for connection abort 
    if (connection_aborted() != 0) { 
     file_put_contents ("con-status.txt", "\nUser terminated the process", FILE_APPEND); 
     die(); 
    } 

} 

file_put_contents ("con-status.txt", "\nAll units completed.", FILE_APPEND); 

EDIT 07-Tháng tư-2017

Nếu ai đó đang sử dụng nhanh -Cgi trên Windows thì anh ta thực sự có thể chấm dứt chuỗi CGI khỏi bộ nhớ khi kết nối bị hủy bỏ bằng cách sử dụng mã sau:

if (connection_aborted() != 0) { apache_child_terminate(); exit; }

+0

lưu ý rằng 'ob_flush' nên được gọi trước khi' flush', nếu đầu ra đệm đang được sử dụng (có thể là ob_end_flush?) Http://stackoverflow.com/questions/4191385/php-buffer-ob-flush-vs-flush – metadings

1

Một cách tôi đã tìm thấy đó là cách dễ nhất để giải quyết vấn đề time-out này là như vậy:

1: đặt một giá trị trên máy chủ như 'xử lý'. Bắt đầu một chuỗi độc lập để thực hiện quá trình xử lý.
2: Cuộc gọi ajax đầu tiên trả về thành công
3: JavaScript trên trang sẽ chuyển sang 'chế độ chờ' sẽ gửi yêu cầu ajax mới cứ 10 hoặc 30 hoặc 60 giây hoặc năm hoặc mười phút hoặc bất kỳ thứ gì (tùy thuộc vào tình huống) để tìm hiểu xem giá trị trên máy chủ vẫn được đặt thành 'xử lý' hay không.
4: Chuỗi độc lập hoàn tất. Nó đặt giá trị trên máy chủ thành 'xong'.
5: JavaScript trên trang thực hiện truy vấn chế độ chờ đợi tiếp theo và trả về 'đã hoàn tất' và dữ liệu thích hợp.

4b: Nếu một khoảng thời gian khiêu dâm trôi qua mà không có 'hoàn thành', nó sẽ bị đăng ký là lỗi. Bao nhiêu thời gian là khiêu dâm phụ thuộc vào tình hình của bạn. Gửi cuộc gọi ajax cập nhật giá trị từ 'đang xử lý' thành 'hủy'. 5b: Chuỗi độc lập định kỳ kiểm tra trạng thái để đảm bảo trạng thái vẫn được đặt thành 'đang xử lý'. Nếu nó thấy một sự thay đổi chế độ để 'hủy' nó hủy bỏ chính nó.

4

Check-out PHP connection_aborted() chức năng. Trong khi thực hiện quá trình xử lý của bạn, đôi khi bạn có thể kiểm tra kết nối bị hủy bỏ để hủy bỏ tiến trình một cách duyên dáng, như một thao tác sẽ thực hiện trong một mô hình luồng tương tác.

+0

Rất tiếc. Tôi thậm chí không biết điều này là có. Cảm ơn! –

+0

@metadings Điều này dường như không hoạt động đối với các yêu cầu ajax. Yêu cầu ajax bị chấm dứt và connection_aborted() vẫn trả về 0. Ngay cả khi tôi đã thử bằng cách đóng trang web vẫn còn các script tiếp tục thực hiện. Nguyên nhân có thể là gì? –

+0

@metadings Hàm connection_aborted() có lỗi và nó sẽ trả về 0 xem lỗi này: https://bugs.php.net/bug.php?id=54062 ... Có tùy chọn nào khác không? –

Các vấn đề liên quan