2020 */
2121namespace PEAR2 \Net \RouterOS ;
2222
23- /**
24- * Used as a holder for the entry cache.
25- */
26- use SplFixedArray ;
27-
2823/**
2924 * Values at {@link Util::exec()} can be casted from this type.
3025 */
@@ -60,7 +55,7 @@ class Util
6055 protected $ menu = '/ ' ;
6156
6257 /**
63- * @var SplFixedArray An array with the numbers of entries in the current menu as
58+ * @var array An array with the numbers of entries in the current menu as
6459 * keys, and the corresponding IDs as values.
6560 */
6661 protected $ idCache = null ;
@@ -260,9 +255,15 @@ public function exec(
260255 * number. If you're using both Util's methods and other means (e.g.
261256 * {@link Client} or {@link Util::exec()}) to add/move/remove entries, the
262257 * cache may end up being out of date. By calling this method right before
263- * targeting an entry with a number, you can ensure number accuracy. Note
264- * that Util's add(), move() and remove() methods automatically clear the
265- * cache. A change in the menu also clears the cache.
258+ * targeting an entry with a number, you can ensure number accuracy.
259+ *
260+ * Note that Util's {@link move()} and {@link remove()} methods
261+ * automatically clear the cache before returning, while {@link add()} adds
262+ * the new entry's ID to the cache as the next number. A change in the menu
263+ * also clears the cache.
264+ *
265+ * Note also that the cache is being rebuilt unconditionally every time you
266+ * use {@link find()} with a callback.
266267 *
267268 * @return $this The Util object itself.
268269 */
@@ -295,8 +296,16 @@ public function clearIdCache()
295296 public function find ()
296297 {
297298 if (func_num_args () === 0 ) {
298- $ this ->refreshIdCache ();
299- return implode (', ' , $ this ->idCache ->toArray ());
299+ if (null === $ this ->idCache ) {
300+ $ idCache = array ();
301+ foreach ($ this ->client ->sendSync (
302+ new Request ($ this ->menu . '/print .proplist=.id ' )
303+ )->getAllOfType (Response::TYPE_DATA ) as $ response ) {
304+ $ idCache [] = $ response ->getArgument ('.id ' );
305+ }
306+ $ this ->idCache = $ idCache ;
307+ }
308+ return implode (', ' , $ this ->idCache );
300309 }
301310 $ idList = '' ;
302311 foreach (func_get_args () as $ criteria ) {
@@ -307,21 +316,28 @@ public function find()
307316 $ idList .= $ response ->getArgument ('.id ' ) . ', ' ;
308317 }
309318 } elseif (is_callable ($ criteria )) {
319+ $ idCache = array ();
310320 foreach ($ this ->client ->sendSync (
311321 new Request ($ this ->menu . '/print ' )
312322 ) as $ response ) {
313323 if ($ criteria ($ response )) {
314324 $ idList .= $ response ->getArgument ('.id ' ) . ', ' ;
315325 }
326+ $ idCache [] = $ response ->getArgument ('.id ' );
316327 }
328+ $ this ->idCache = $ idCache ;
317329 } else {
318- $ this ->refreshIdCache ();
330+ $ this ->find ();
319331 if (is_int ($ criteria )) {
320- $ idList = $ this ->idCache [$ criteria ] . ', ' ;
332+ if (isset ($ this ->idCache [$ criteria ])) {
333+ $ idList = $ this ->idCache [$ criteria ] . ', ' ;
334+ }
321335 } else {
322336 $ criteria = (string )$ criteria ;
323337 if ($ criteria === (string )(int )$ criteria ) {
324- $ idList .= $ this ->idCache [(int )$ criteria ] . ', ' ;
338+ if (isset ($ this ->idCache [(int )$ criteria ])) {
339+ $ idList .= $ this ->idCache [(int )$ criteria ] . ', ' ;
340+ }
325341 } elseif (false === strpos ($ criteria , ', ' )) {
326342 $ idList .= $ criteria . ', ' ;
327343 } else {
@@ -361,7 +377,7 @@ public function find()
361377 public function get ($ number , $ value_name )
362378 {
363379 if (is_int ($ number ) || ((string )$ number === (string )(int )$ number )) {
364- $ this ->refreshIdCache ();
380+ $ this ->find ();
365381 if (isset ($ this ->idCache [(int )$ number ])) {
366382 $ number = $ this ->idCache [(int )$ number ];
367383 } else {
@@ -513,11 +529,13 @@ public function add(array $values)
513529 foreach ($ values as $ name => $ value ) {
514530 $ addRequest ->setArgument ($ name , $ value );
515531 }
516- $ idList .= $ this ->client ->sendSync ($ addRequest )->getArgument ('ret ' )
517- . ', ' ;
532+ $ id = $ this ->client ->sendSync ($ addRequest )->getArgument ('ret ' );
533+ if (null !== $ this ->idCache ) {
534+ $ this ->idCache [] = $ id ;
535+ }
536+ $ idList .= $ id . ', ' ;
518537 $ addRequest ->removeAllArguments ();
519538 }
520- $ this ->clearIdCache ();
521539 return rtrim ($ idList , ', ' );
522540 }
523541
@@ -555,6 +573,14 @@ public function move($numbers, $destination)
555573 /**
556574 * Puts a file on RouterOS's file system.
557575 *
576+ * Puts a file on RouterOS's file system, regardless of the current menu.
577+ * Note that this is a VERY VERY VERY time consuming method - it takes a
578+ * minimum of a little over 4 seconds, most of which are in sleep. It waits
579+ * 2 seconds after a file is first created (required to actually start
580+ * writing to the file), and another 2 seconds after its contents is written
581+ * (performed in order to verify success afterwards). If you want an
582+ * efficient way of transferring files, use (T)FTP.
583+ *
558584 * @param string $filename The filename to write data in.
559585 * @param string $data The data the file is going to have.
560586 * @param bool $overwrite Whether to overwrite the file if it exists.
@@ -606,29 +632,19 @@ public function filePutContents($filename, $data, $overwrite = false)
606632 public function fileGetContents ($ filename , $ tmpScriptName = null )
607633 {
608634 $ checkRequest = new Request (
609- '/file print ' ,
635+ '/file/ print ' ,
610636 Query::where ('name ' , $ filename )
611637 );
612638 if (1 === count ($ this ->client ->sendSync ($ checkRequest ))) {
613639 return false ;
614640 }
615- $ name = $ this ->_exec (
641+ $ contents = $ this ->_exec (
616642 '/system script set $"_" source=[/file get $filename contents] ' ,
617643 array ('filename ' => $ filename ),
618644 null ,
619645 $ tmpScriptName ,
620646 true
621647 );
622- $ printRequest = new Request (
623- '/system script print .proplist=source ' ,
624- Query::where ('name ' , $ name )
625- );
626- $ contents = $ this ->client ->sendSync (
627- $ printRequest
628- )->getArgument ('source ' );
629- $ removeRequest = new Request ('/system script remove ' );
630- $ removeRequest ->setArgument ('numbers ' , $ name );
631- $ this ->client ->sendSync ($ removeRequest );
632648 return $ contents ;
633649 }
634650
@@ -653,31 +669,11 @@ protected function doBulk($what, array $args = array())
653669 return $ this ->client ->sendSync ($ bulkRequest );
654670 }
655671
656- /**
657- * Refresh the id cache, if needed.
658- *
659- * @return void
660- */
661- protected function refreshIdCache ()
662- {
663- if (null === $ this ->idCache ) {
664- $ idCache = array ();
665- foreach ($ this ->client ->sendSync (
666- new Request ($ this ->menu . '/print .proplist=.id ' )
667- )->getAllOfType (Response::TYPE_DATA ) as $ response ) {
668- $ id = $ response ->getArgument ('.id ' );
669- $ idCache [hexdec (substr ($ id , 1 ))] = $ id ;
670- }
671- ksort ($ idCache , SORT_NUMERIC );
672- $ this ->idCache = SplFixedArray::fromArray (array_values ($ idCache ));
673- }
674- }
675-
676672 /**
677673 * Executes a RouterOS script.
678674 *
679- * Same as the public equivalent, with the addition of allowing you not to
680- * remove the script after you're done .
675+ * Same as the public equivalent, with the addition of allowing you to get
676+ * the contents of the script post execution, instead of removing it .
681677 *
682678 * @param string $source A script to execute.
683679 * @param array $params An array of local variables to make available in
@@ -694,7 +690,7 @@ protected function refreshIdCache()
694690 * "/system script" under a random name (prefixed with the computer's
695691 * name), and is removed after execution. To eliminate any possibility
696692 * of name clashes, you can specify your own name.
697- * @param bool $keep Whether to keep the script after execution.
693+ * @param bool $get Whether to keep the script after execution.
698694 *
699695 * @return ResponseCollection|string If the script was not added
700696 * successfully before execution, the ResponseCollection from the add
@@ -706,7 +702,7 @@ private function _exec(
706702 array $ params = array (),
707703 $ policy = null ,
708704 $ name = null ,
709- $ keep = false
705+ $ get = false
710706 ) {
711707 $ request = new Request ('/system/script/add ' );
712708 if (null === $ name ) {
@@ -733,13 +729,17 @@ private function _exec(
733729 $ request ->setArgument ('number ' , $ name );
734730 $ result = $ this ->client ->sendSync ($ request );
735731
736- if ($ keep ) {
737- return $ name ;
738- } else {
739- $ request = new Request ('/system/script/remove ' );
740- $ request ->setArgument ('numbers ' , $ name );
741- $ this ->client ->sendSync ($ request );
732+ if ($ get ) {
733+ $ result = $ this ->client ->sendSync (
734+ new Request (
735+ '/system/script/print .proplist="source" ' ,
736+ Query::where ('name ' , $ name )
737+ )
738+ )->getArgument ('source ' );
742739 }
740+ $ request = new Request ('/system/script/remove ' );
741+ $ request ->setArgument ('numbers ' , $ name );
742+ $ this ->client ->sendSync ($ request );
743743 }
744744
745745 return $ result ;
0 commit comments