package.xml0000644000175100017510000000750013767106674013124 0ustar mentionmention inotify pecl.php.net Inotify Inotify bindings for PHP Arnaud Le Blanc lbarnaud arnaud.lb@gmail.com yes 2020-12-18 3.0.0 0.1.2 stable stable PHP License * PHP 8 compatible release 7.0.0 1.4.0 inotify 2016-01-30 2.0.0 0.1.2 stable stable PHP License * PHP 7 compatible release 2012-05-04 0.1.6 0.1.2 stable stable PHP License * Repackage * Stable 2012-03-05 0.1.5 0.1.2 beta beta * PHP 5.4 compatibility 2009-05-19 0.1.4 0.1.2 beta beta * Repackage 2008-11-03 0.1.3 0.1.2 beta beta * Cosmetic changes (improved reflection support, etc.) * Documented at php.net 2008-10-22 0.1.2 0.1.2 beta beta * Initial release inotify-3.0.0/tests/002.phpt0000644000175100017510000000606413767106674015470 0ustar mentionmention--TEST-- inotify --SKIPIF-- --FILE-- 0) { $events = inotify_read($ino); if ($events === false) break; if (is_array($events)) { $all_events = array_merge($all_events, $events); $event_count -= count($events); } } function mysort($a,$b) { $a = print_r($a,true); $b = print_r($b,true); if ($a > $b) return 1; if ($a < $b) return -1; return 0; } // events do not always arrive in the same order, // we need to sort them to have a reproductible output usort($all_events,'mysort'); echo 'inotify_read($ino): '; var_dump($all_events); $ret = inotify_rm_watch($ino,$watch); echo 'inofity_rm_watch($ino,$watch): '; var_dump($ret); echo '$watch: '; var_dump($watch); $ret = fclose($ino); echo 'fclose($ino): '; var_dump($ret); echo '$ino: '; var_dump($ino); ?> --EXPECTF-- inotify_init(): resource(%d) of type (stream) fclose($ino): bool(true) $ino: resource(%d) of type (Unknown) inotify_init(): resource(%d) of type (stream) inotify_queue_len($ino): int(0) inotify_add_watch($ino, __FILE__, IN_ATTRIB|IN_OPEN|IN_CLOSE_NOWRITE): int(%d) inotify_add_watch($ino, dirname(__FILE__), IN_ATTRIB|IN_OPEN|IN_CLOSE_NOWRITE): int(%d) inotify_queue_len($ino): int(%d) inotify_read($ino): array(6) { [0]=> array(4) { ["wd"]=> int(%d) ["mask"]=> int(16) ["cookie"]=> int(0) ["name"]=> string(0) "" } [1]=> array(4) { ["wd"]=> int(%d) ["mask"]=> int(32) ["cookie"]=> int(0) ["name"]=> string(0) "" } [2]=> array(4) { ["wd"]=> int(%d) ["mask"]=> int(4) ["cookie"]=> int(0) ["name"]=> string(0) "" } [3]=> array(4) { ["wd"]=> int(%d) ["mask"]=> int(16) ["cookie"]=> int(0) ["name"]=> string(7) "002.php" } [4]=> array(4) { ["wd"]=> int(%d) ["mask"]=> int(32) ["cookie"]=> int(0) ["name"]=> string(7) "002.php" } [5]=> array(4) { ["wd"]=> int(%d) ["mask"]=> int(4) ["cookie"]=> int(0) ["name"]=> string(7) "002.php" } } inofity_rm_watch($ino,$watch): bool(true) $watch: int(%d) fclose($ino): bool(true) $ino: resource(%d) of type (Unknown) inotify-3.0.0/CREDITS0000644000175100017510000000003013767106674014133 0ustar mentionmentionInotify Arnaud Le Blanc inotify-3.0.0/EXPERIMENTAL0000644000175100017510000000000013767106674014730 0ustar mentionmentioninotify-3.0.0/LICENSE0000644000175100017510000000622213767106674014131 0ustar mentionmention-------------------------------------------------------------------- The PHP License, version 3.01 Copyright (c) 1999 - 2008 The PHP Group. All rights reserved. -------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name "PHP" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact group@php.net. 4. Products derived from this software may not be called "PHP", nor may "PHP" appear in their name, without prior written permission from group@php.net. You may indicate that your software works in conjunction with PHP by saying "Foo for PHP" instead of calling it "PHP Foo" or "phpfoo" 5. The PHP Group may publish revised and/or new versions of the license from time to time. Each version will be given a distinguishing version number. Once covered code has been published under a particular version of the license, you may always continue to use it under the terms of that version. You may also choose to use such covered code under the terms of any subsequent version of the license published by the PHP Group. No one other than the PHP Group has the right to modify the terms applicable to covered code created under this License. 6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes PHP software, freely available from ". THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------- This software consists of voluntary contributions made by many individuals on behalf of the PHP Group. The PHP Group can be contacted via Email at group@php.net. For more information on the PHP Group and the PHP project, please see . PHP includes the Zend Engine, freely available at . inotify-3.0.0/README.md0000644000175100017510000000042413767106674014401 0ustar mentionmention# PHP Inotify Inotify bindings for PHP 5 and PHP 7 This extension exposes the inotify API and some additional functions. ## Install * PHP 5: pecl install inotify-0.1.6 * PHP 7: pecl install inotify ## Documentation Documentation is available at https://php.net/inotify inotify-3.0.0/inotify.c0000644000175100017510000002350213767106674014751 0ustar mentionmention/* +----------------------------------------------------------------------+ | inotify | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Arnaud Le Blanc | +----------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_inotify.h" /* {{{ arginfo */ ZEND_BEGIN_ARG_INFO_EX(arginfo_inotify_init, 0, ZEND_RETURN_VALUE, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_inotify_add_watch, 0, ZEND_RETURN_VALUE, 3) ZEND_ARG_INFO(0, inotify_instance) ZEND_ARG_INFO(0, pathname) ZEND_ARG_INFO(0, mask) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_inotify_rm_watch, 0, ZEND_RETURN_VALUE, 2) ZEND_ARG_INFO(0, inotify_instance) ZEND_ARG_INFO(0, mask) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_inotify_queue_len, 0, ZEND_RETURN_VALUE, 1) ZEND_ARG_INFO(0, inotify_instance) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_inotify_read, 0, ZEND_RETURN_VALUE, 1) ZEND_ARG_INFO(0, inotify_instance) ZEND_END_ARG_INFO() /* }}} */ /* {{{ inotify_functions[] */ #if ZEND_MODULE_API_NO >= 20071006 const #endif zend_function_entry inotify_functions[] = { PHP_FE(inotify_init, arginfo_inotify_init) PHP_FE(inotify_add_watch, arginfo_inotify_add_watch) PHP_FE(inotify_rm_watch, arginfo_inotify_rm_watch) PHP_FE(inotify_queue_len, arginfo_inotify_queue_len) PHP_FE(inotify_read, arginfo_inotify_read) {NULL, NULL, NULL} /* Must be the last line in inotify_functions[] */ }; /* }}} */ /* {{{ inotify_module_entry */ zend_module_entry inotify_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif "inotify", inotify_functions, PHP_MINIT(inotify), PHP_MSHUTDOWN(inotify), NULL, /* Replace with NULL if there's nothing to do at request start */ NULL, /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(inotify), #if ZEND_MODULE_API_NO >= 20010901 PHP_INOTIFY_VERSION, #endif STANDARD_MODULE_PROPERTIES }; /* }}} */ #ifdef COMPILE_DL_INOTIFY ZEND_GET_MODULE(inotify) #endif /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(inotify) { /* the following are legal, implemented events that user-space can watch for */ REGISTER_LONG_CONSTANT("IN_ACCESS", IN_ACCESS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_MODIFY", IN_MODIFY, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_ATTRIB", IN_ATTRIB, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_CLOSE_WRITE", IN_CLOSE_WRITE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_CLOSE_NOWRITE", IN_CLOSE_NOWRITE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_OPEN", IN_OPEN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_MOVED_FROM", IN_MOVED_FROM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_MOVED_TO", IN_MOVED_TO, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_CREATE", IN_CREATE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_DELETE", IN_DELETE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_DELETE_SELF", IN_DELETE_SELF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_MOVE_SELF", IN_MOVE_SELF, CONST_CS | CONST_PERSISTENT); /* the following are legal events. they are sent as needed to any watch */ REGISTER_LONG_CONSTANT("IN_UNMOUNT", IN_UNMOUNT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_Q_OVERFLOW", IN_Q_OVERFLOW, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_IGNORED", IN_IGNORED, CONST_CS | CONST_PERSISTENT); /* helper events */ REGISTER_LONG_CONSTANT("IN_CLOSE", IN_CLOSE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_MOVE", IN_MOVE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_ALL_EVENTS", IN_ALL_EVENTS, CONST_CS | CONST_PERSISTENT); /* special flags */ REGISTER_LONG_CONSTANT("IN_ONLYDIR", IN_ONLYDIR, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_DONT_FOLLOW", IN_DONT_FOLLOW, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_MASK_ADD", IN_MASK_ADD, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_ISDIR", IN_ISDIR, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IN_ONESHOT", IN_ONESHOT, CONST_CS | CONST_PERSISTENT); return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(inotify) { return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(inotify) { php_info_print_table_start(); php_info_print_table_row(2, "Version", PHP_INOTIFY_VERSION); php_info_print_table_end(); } /* }}} */ static int php_inotify_queue_len(const int fd) /* {{{ */ { int ret; int queue_len; ret = ioctl(fd, FIONREAD, &queue_len); if (ret < 0) { php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); return 0; } return queue_len; } /* }}} */ /* {{{ proto resource inotify_init() Initializes a new inotify instance and returns an inotify resource associated with the new inotify event queue */ PHP_FUNCTION(inotify_init) { php_stream *stream; int fd; fd = inotify_init(); if (fd == -1) { switch(errno) { INOTIFY_ERROR_CASE(INIT,EMFILE); INOTIFY_ERROR_CASE(INIT,ENFILE); INOTIFY_ERROR_CASE(INIT,ENOMEM); INOTIFY_DEFAULT_ERROR(errno); } RETURN_FALSE; } stream = php_stream_fopen_from_fd(fd, "r", NULL); stream->flags |= PHP_STREAM_FLAG_NO_SEEK; php_stream_to_zval(stream, return_value); } /* }}} */ /* {{{ proto int inotify_add_watch(resource inofity_instance, string pathname, int mask) Adds a watch to an initialized inotify instance */ PHP_FUNCTION(inotify_add_watch) { zval *zstream; php_stream *stream; char *pathname; size_t pathname_len; long mask, wd; int fd; if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsl", &zstream, &pathname, &pathname_len, &mask) == FAILURE) { return; } if (php_check_open_basedir(pathname)) { RETURN_FALSE; } php_stream_from_zval(stream, zstream); INOTIFY_FD(stream, fd); wd = inotify_add_watch(fd, pathname, mask); if (wd == -1) { switch(errno) { INOTIFY_ERROR_CASE(ADD_WATCH,EACCES); INOTIFY_ERROR_CASE(ADD_WATCH,EBADF); INOTIFY_ERROR_CASE(ADD_WATCH,EINVAL); INOTIFY_ERROR_CASE(ADD_WATCH,ENOMEM); INOTIFY_ERROR_CASE(ADD_WATCH,ENOSPC); INOTIFY_DEFAULT_ERROR(errno); } RETURN_FALSE; } RETURN_LONG(wd); } /* }}} */ /* {{{ proto bool inotify_rm_watch(resource inotify_instance, int inotify_watch_descriptor) Remove an existing watch from the given inotify instance */ PHP_FUNCTION(inotify_rm_watch) { zval *zstream; php_stream *stream; int fd; long wd; if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &zstream, &wd) == FAILURE) { return; } php_stream_from_zval(stream, zstream); INOTIFY_FD(stream, fd); if (inotify_rm_watch(fd, wd) == -1) { switch(errno) { INOTIFY_ERROR_CASE(RM_WATCH,EINVAL); INOTIFY_DEFAULT_ERROR(errno); } RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ proto int inotify_queue_len(resource inotify_instance) Returns an int upper than zero if events are pending */ PHP_FUNCTION(inotify_queue_len) { zval *zstream; php_stream *stream; int fd; long queue_len; if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream) == FAILURE) { return; } php_stream_from_zval(stream, zstream); INOTIFY_FD(stream, fd); queue_len = php_inotify_queue_len(fd); RETURN_LONG(queue_len); } /* }}} */ /* {{{ proto array inotify_read(resource inotify_instance) read()s inotify events */ PHP_FUNCTION(inotify_read) { zval *zstream; php_stream *stream; char *readbuf = NULL; size_t readbuf_size = 0; ssize_t readden, i; struct inotify_event *event; zval event_ary; int fd; if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream) == FAILURE) { return; } php_stream_from_zval(stream, zstream); INOTIFY_FD(stream, fd); readbuf_size = (double) php_inotify_queue_len(fd) * 1.6; if (readbuf_size < 1) { readbuf_size = sizeof(struct inotify_event) + 32; } do { readbuf = erealloc(readbuf, readbuf_size); readden = read(fd, readbuf, readbuf_size); /* If the passed buffer is too small to contain all the * pending events, the kernel may return an error and * forces us to pass a bigger one. */ if (INOTIFY_BUF_TOO_SMALL(readden,errno)) { readbuf_size *= 1.6; continue; } else if (readden < 0) { if (errno != EAGAIN) { php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); } efree(readbuf); RETURN_FALSE; } } while (INOTIFY_BUF_TOO_SMALL(readden,errno)); array_init(return_value); for(i = 0; i < readden; i += sizeof(struct inotify_event) + event->len) { event = (struct inotify_event *)&readbuf[i]; array_init(&event_ary); add_assoc_long(&event_ary, "wd", event->wd); add_assoc_long(&event_ary, "mask", event->mask); add_assoc_long(&event_ary, "cookie", event->cookie); add_assoc_string(&event_ary, "name", (event->len > 0 ? event->name : "")); add_next_index_zval(return_value, &event_ary); } efree(readbuf); } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ inotify-3.0.0/php_inotify.h0000644000175100017510000000637713767106674015640 0ustar mentionmention/* +----------------------------------------------------------------------+ | inotify | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Arnaud Le Blanc | +----------------------------------------------------------------------+ */ /* $Id$ */ #ifndef PHP_INOTIFY_H #define PHP_INOTIFY_H extern zend_module_entry inotify_module_entry; #define phpext_inotify_ptr &inotify_module_entry #ifdef ZTS #include "TSRM.h" #endif #include PHP_MINIT_FUNCTION(inotify); PHP_MSHUTDOWN_FUNCTION(inotify); PHP_MINFO_FUNCTION(inotify); PHP_FUNCTION(inotify_init); PHP_FUNCTION(inotify_add_watch); PHP_FUNCTION(inotify_rm_watch); PHP_FUNCTION(inotify_queue_len); PHP_FUNCTION(inotify_read); #define PHP_INOTIFY_VERSION "3.0.0" #define INOTIFY_BUF_TOO_SMALL(ret,errno) \ ((ret) == 0 || ((ret) == -1 && (errno) == EINVAL)) #define INOTIFY_FD(stream, fd) \ php_stream_cast((stream), PHP_STREAM_AS_FD_FOR_SELECT, (void*)&(fd), 1); /* Define some error messages for the error numbers set by inotify_*() functions, as strerror() messages are not always usefull here */ #define INOTIFY_INIT_EMFILE \ "The user limit on the total number of inotify instances has been reached" #define INOTIFY_INIT_ENFILE \ "The system limit on the total number of file descriptors has been reached" #define INOTIFY_INIT_ENOMEM \ "Insufficient kernel memory is available" #define INOTIFY_ADD_WATCH_EACCES \ "Read access to the given file is not permitted" #define INOTIFY_ADD_WATCH_EBADF \ "The given file descriptor is not valid" #define INOTIFY_ADD_WATCH_EINVAL \ "The given event mask contains no valid events; or the given file descriptor is not valid" #define INOTIFY_ADD_WATCH_ENOMEM \ "Insufficient kernel memory was available" #define INOTIFY_ADD_WATCH_ENOSPC \ "The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource" #define INOTIFY_RM_WATCH_EINVAL \ "The file descriptor is not an inotify instance or the watch descriptor is invalid" #define INOTIFY_ERROR_CASE(func, errno) \ case (errno): \ php_error_docref(NULL, E_WARNING, INOTIFY_##func##_##errno); \ break; #define INOTIFY_DEFAULT_ERROR(errno) \ default: \ php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); \ break; #endif /* PHP_INOTIFY_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ inotify-3.0.0/config.m40000644000175100017510000000073013767106674014631 0ustar mentionmentiondnl $Id$ dnl config.m4 for extension inotify PHP_ARG_ENABLE(inotify, whether to enable inotify support, [ --enable-inotify Enable inotify support]) if test "$PHP_INOTIFY" != "no"; then AC_TRY_RUN([ #include void testfunc(int (*passedfunc)()) { } int main() { testfunc(inotify_init); return 0; } ],[],[ AC_MSG_ERROR(Your system does not support inotify) ]) PHP_NEW_EXTENSION(inotify, inotify.c, $ext_shared) fi inotify-3.0.0/inotify.php0000644000175100017510000000427113767106674015320 0ustar mentionmention 1, // $watch_descriptor 'mask' => 4, // IN_ATTRIB bit is set 'cookie' => 0, // unique id to connect related events (e.g. // IN_MOVE_FROM and IN_MOVE_TO events) 'name' => '', // the name of a file (e.g. if we monitored changes // in a directory) ), ); print_r($events); // If we do not want to block on inotify_read(), we may // - Use stream_select() on $fd: $read = array($fd); $write = null; $except = null; stream_select($read,$write,$except,0); // - Use stream_set_blocking() on $fd stream_set_blocking($fd, 0); inotify_read($fd); // Does no block, and return false if no events are pending // - Use inotify_queue_len() to check if event queue is not empty $queue_len = inotify_queue_len($fd); // If > 0, we can be assured that // inotify_read() will not block // We do not need anymore to watch events, closing them // Stop watching __FILE__ for metadata changes inotify_rm_watch($fd, $watch_descriptor); // Close our inotify instance // This may have closed all watches if we haven't already closed them fclose($fd); ?> inotify-3.0.0/tail.php0000755000175100017510000000226613767106674014575 0ustar mentionmention#!/usr/bin/php