/** * Puts a file on RouterOS's file system. * * Puts a file on RouterOS's file system, regardless of the current menu. * Note that this is a **VERY VERY VERY** time consuming method - it takes a * minimum of a little over 4 seconds, most of which are in sleep. It waits * 2 seconds after a file is first created (required to actually start * writing to the file), and another 2 seconds after its contents is written * (performed in order to verify success afterwards). * Similarly for removal (when $data is NULL) - there are two seconds in * sleep, used to verify the file was really deleted. * * If you want an efficient way of transferring files, use (T)FTP. * If you want an efficient way of removing files, use * {@link static::setMenu()} to move to the "/file" menu, and call * {@link static::remove()} without performing verification afterwards. * * @param string $filename The filename to write data in. * @param string|resource|null $data The data the file is going to have * as a string or a seekable stream. * Setting the value to NULL removes a file of this name. * If a seekable stream is provided, it is sent from its current * posistion to its end, and the pointer is seeked back to its current * position after sending. * Non seekable streams, as well as all other types, are casted to a * string. * @param bool $overwrite Whether to overwrite the file if * it exists. * * @return bool TRUE on success, FALSE on failure. */ public function filePutContents($filename, $data, $overwrite = false) { $printRequest = new Request('/file/print .proplist=""', Query::where('name', $filename)); $fileExists = count($this->client->sendSync($printRequest)) > 1; if (null === $data) { if (!$fileExists) { return false; } $removeRequest = new Request('/file/remove'); $this->client->sendSync($removeRequest->setArgument('numbers', $filename)); //Required for RouterOS to REALLY remove the file. sleep(2); return !(count($this->client->sendSync($printRequest)) > 1); } if (!$overwrite && $fileExists) { return false; } $result = $this->client->sendSync($printRequest->setArgument('file', $filename)); if (count($result->getAllOfType(Response::TYPE_ERROR)) > 0) { return false; } //Required for RouterOS to write the initial file. sleep(2); $setRequest = new Request('/file/set contents=""'); $setRequest->setArgument('numbers', $filename); $this->client->sendSync($setRequest); $this->client->sendSync($setRequest->setArgument('contents', $data)); //Required for RouterOS to write the file's new contents. sleep(2); $fileSize = $this->client->sendSync($printRequest->setArgument('file', null)->setArgument('.proplist', 'size'))->getProperty('size'); if (Stream::isStream($fileSize)) { $fileSize = stream_get_contents($fileSize); } if (Communicator::isSeekableStream($data)) { return Communicator::seekableStreamLength($data) == $fileSize; } else { return sprintf('%u', strlen((string) $data)) === $fileSize; } }
/** * Decodes the lenght of the incoming message. * * Decodes the lenght of the incoming message, as specified by the RouterOS * API. * * Difference with the non private function is that this one doesn't perform * locking if the connection is a persistent one. * * @param T\Stream $trans The transmitter from which to decode the length of * the incoming message. * * @return int The decoded length. */ private static function _decodeLength(T\Stream $trans) { $byte = ord($trans->receive(1, 'initial length byte')); if ($byte & 0x80) { if (($byte & 0xc0) === 0x80) { return (($byte & 077) << 8) + ord($trans->receive(1)); } elseif (($byte & 0xe0) === 0xc0) { $rem = unpack('n~', $trans->receive(2)); return (($byte & 037) << 16) + $rem['~']; } elseif (($byte & 0xf0) === 0xe0) { $rem = unpack('n~/C~~', $trans->receive(3)); return (($byte & 017) << 24) + ($rem['~'] << 8) + $rem['~~']; } elseif (($byte & 0xf8) === 0xf0) { $rem = unpack('N~', $trans->receive(4)); return ($byte & 07) * 0x100000000 + (double) sprintf('%u', $rem['~']); } throw new NotSupportedException('Unknown control byte encountered.', NotSupportedException::CODE_CONTROL_BYTE, null, $byte); } else { return $byte; } }