mirror of
https://github.com/danog/tgseclib.git
synced 2024-11-27 04:34:45 +01:00
- added Crypt_RSA
- added RSA public key authentication to Net_SSH2 git-svn-id: http://phpseclib.svn.sourceforge.net/svnroot/phpseclib/trunk@62 21d32557-59b3-4da0-833f-c5933fad653e
This commit is contained in:
parent
ec75e4fc32
commit
a882a3a41f
1929
phpseclib/Crypt/RSA.php
Normal file
1929
phpseclib/Crypt/RSA.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -69,7 +69,7 @@
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVI Jim Wigginton
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt
|
||||
* @version $Id: BigInteger.php,v 1.16 2009-11-23 19:06:07 terrafrost Exp $
|
||||
* @version $Id: BigInteger.php,v 1.17 2009-12-03 08:18:53 terrafrost Exp $
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
@ -291,7 +291,7 @@ class Math_BigInteger {
|
||||
|
||||
break;
|
||||
// converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
|
||||
case MATH_BIGINTEGER_MODE_INTERNAL:
|
||||
default:
|
||||
while (strlen($x)) {
|
||||
$this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26));
|
||||
}
|
||||
@ -332,7 +332,7 @@ class Math_BigInteger {
|
||||
$this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
|
||||
$this->is_negative = false;
|
||||
break;
|
||||
case MATH_BIGINTEGER_MODE_INTERNAL:
|
||||
default:
|
||||
$x = ( strlen($x) & 1 ) ? '0' . $x : $x;
|
||||
$temp = new Math_BigInteger(pack('H*', $x), 256);
|
||||
$this->value = $temp->value;
|
||||
@ -356,7 +356,7 @@ class Math_BigInteger {
|
||||
// results then doing it on '-1' does (modInverse does $x[0])
|
||||
$this->value = (string) $x;
|
||||
break;
|
||||
case MATH_BIGINTEGER_MODE_INTERNAL:
|
||||
default:
|
||||
$temp = new Math_BigInteger();
|
||||
|
||||
// array(10000000) is 10**7 in base-2**26. 10**7 is the closest to 2**26 we can get without passing it.
|
||||
@ -1054,7 +1054,6 @@ class Math_BigInteger {
|
||||
|
||||
// the above for loop is what the previous comment was talking about. the
|
||||
// following for loop is the "one with nested for loops"
|
||||
|
||||
for ($i = 1; $i < $x_length; $i++) {
|
||||
$carry = 0;
|
||||
|
||||
@ -1272,6 +1271,12 @@ class Math_BigInteger {
|
||||
return array($this->_normalize($quotient), $this->_normalize($remainder));
|
||||
}
|
||||
|
||||
if (count($y->value) == 1) {
|
||||
$temp = $this->_divide_digit($y->value[0]);
|
||||
$temp[0]->is_negative = $this->is_negative != $y->is_negative;
|
||||
return array($this->_normalize($temp[0]), $this->_normalize($temp[1]));
|
||||
}
|
||||
|
||||
static $zero;
|
||||
if (!isset($zero)) {
|
||||
$zero = new Math_BigInteger();
|
||||
@ -1399,6 +1404,32 @@ class Math_BigInteger {
|
||||
return array($this->_normalize($quotient), $this->_normalize($x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides a BigInteger by a regular integer
|
||||
*
|
||||
* abc / x = a00 / x + b0 / x + c / x
|
||||
*
|
||||
* @param Math_BigInteger $divisor
|
||||
* @return Array
|
||||
* @access public
|
||||
*/
|
||||
function _divide_digit($divisor)
|
||||
{
|
||||
$carry = 0;
|
||||
$result = new Math_BigInteger();
|
||||
|
||||
for ($i = count($this->value) - 1; $i >= 0; $i--) {
|
||||
$temp = 0x4000000 * $carry + $this->value[$i];
|
||||
$result->value[$i] = floor($temp / $divisor);
|
||||
$carry = fmod($temp, $divisor);
|
||||
}
|
||||
|
||||
$remainder = new Math_BigInteger();
|
||||
$remainder->value = array($carry);
|
||||
|
||||
return array($result, $remainder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*
|
||||
@ -1790,7 +1821,7 @@ class Math_BigInteger {
|
||||
$result = $result->subtract($n);
|
||||
}
|
||||
|
||||
return $result->_normalize();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1810,7 +1841,7 @@ class Math_BigInteger {
|
||||
$temp->value = array_merge($this->_array_repeat(0, $k), $this->value);
|
||||
|
||||
list(, $temp) = $temp->divide($n);
|
||||
return $temp->_normalize();
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2538,14 +2569,15 @@ class Math_BigInteger {
|
||||
$size = strlen($max) - 1;
|
||||
$random = '';
|
||||
|
||||
$bytes = $size & 3;
|
||||
$bytes = $size & 1;
|
||||
for ($i = 0; $i < $bytes; $i++) {
|
||||
$random.= chr($generator(0, 255));
|
||||
}
|
||||
|
||||
$blocks = $size >> 2;
|
||||
$blocks = $size >> 1;
|
||||
for ($i = 0; $i < $blocks; $i++) {
|
||||
$random.= pack('N', $generator(-2147483648, 0x7FFFFFFF));
|
||||
// mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
|
||||
$random.= pack('n', $generator(0, 0xFFFF));
|
||||
}
|
||||
|
||||
$temp = new Math_BigInteger($random, 256);
|
||||
@ -2600,6 +2632,7 @@ class Math_BigInteger {
|
||||
}
|
||||
|
||||
$x = $this->random($min, $max);
|
||||
|
||||
$x->value = gmp_nextprime($x->value);
|
||||
|
||||
if ($x->compare($max) <= 0) {
|
||||
@ -2628,7 +2661,6 @@ class Math_BigInteger {
|
||||
}
|
||||
|
||||
$x = $this->random($min, $max);
|
||||
|
||||
if ($x->equals($two)) {
|
||||
return $x;
|
||||
}
|
||||
@ -2643,19 +2675,19 @@ class Math_BigInteger {
|
||||
$x = $x->add($one);
|
||||
}
|
||||
break;
|
||||
case MATH_BIGINTEGER_MODE_INTERNAL:
|
||||
default:
|
||||
$x->value[0] |= 1;
|
||||
}
|
||||
|
||||
// if we've seen this number twice before, assume there are no prime numbers within the given range
|
||||
if (in_array($x, $repeat1)) {
|
||||
if (in_array($x, $repeat2)) {
|
||||
if (in_array($x->value, $repeat1)) {
|
||||
if (in_array($x->value, $repeat2)) {
|
||||
return false;
|
||||
} else {
|
||||
$repeat2[] = $x;
|
||||
$repeat2[] = $x->value;
|
||||
}
|
||||
} else {
|
||||
$repeat1[] = $x;
|
||||
$repeat1[] = $x->value;
|
||||
}
|
||||
} while (!$x->isPrime());
|
||||
|
||||
@ -2709,7 +2741,7 @@ class Math_BigInteger {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case MATH_BIGINTEGER_MODE_INTERNAL:
|
||||
default:
|
||||
if ($this->value == array(2)) {
|
||||
return true;
|
||||
}
|
||||
@ -2843,7 +2875,7 @@ class Math_BigInteger {
|
||||
function _rshift($shift)
|
||||
{
|
||||
if ($shift == 0) {
|
||||
$this->_normalize();
|
||||
return;
|
||||
}
|
||||
|
||||
$num_digits = floor($shift / 26);
|
||||
|
@ -65,7 +65,7 @@
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt
|
||||
* @version $Id: SSH1.php,v 1.13 2009-11-23 19:06:07 terrafrost Exp $
|
||||
* @version $Id: SSH1.php,v 1.14 2009-12-03 08:18:53 terrafrost Exp $
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
@ -1016,6 +1016,17 @@ class Net_SSH1 {
|
||||
*/
|
||||
function _rsa_crypt($m, $key)
|
||||
{
|
||||
/*
|
||||
if (!class_exists('Crypt_RSA')) {
|
||||
require_once('Crypt/RSA.php');
|
||||
}
|
||||
|
||||
$rsa = new Crypt_RSA();
|
||||
$rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
|
||||
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
|
||||
return $rsa->encrypt($m);
|
||||
*/
|
||||
|
||||
// To quote from protocol-1.5.txt:
|
||||
// The most significant byte (which is only partial as the value must be
|
||||
// less than the public modulus, which is never a power of two) is zero.
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* Here's a short example of how to use this library:
|
||||
* Here's are some examples of how to use this library:
|
||||
* <code>
|
||||
* <?php
|
||||
* include('Net/SSH2.php');
|
||||
@ -21,6 +21,25 @@
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* <code>
|
||||
* <?php
|
||||
* include('Crypt/RSA.php');
|
||||
* include('Net/SSH2.php');
|
||||
*
|
||||
* $key = new Crypt_RSA();
|
||||
* //$key->setPassword('whatever');
|
||||
* $key->loadKey(file_get_contents('privatekey'));
|
||||
*
|
||||
* $ssh = new Net_SSH2('www.domain.tld');
|
||||
* if (!$ssh->login('username', $key)) {
|
||||
* exit('Login Failed');
|
||||
* }
|
||||
*
|
||||
* echo $ssh->exec('pwd');
|
||||
* echo $ssh->exec('ls -la');
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* LICENSE: This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
@ -41,7 +60,7 @@
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt
|
||||
* @version $Id: SSH2.php,v 1.27 2009-11-26 06:41:34 terrafrost Exp $
|
||||
* @version $Id: SSH2.php,v 1.28 2009-12-03 08:18:53 terrafrost Exp $
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
@ -497,7 +516,6 @@ class Net_SSH2 {
|
||||
51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
|
||||
52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
|
||||
53 => 'NET_SSH2_MSG_USERAUTH_BANNER',
|
||||
60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ',
|
||||
|
||||
80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
|
||||
81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
|
||||
@ -546,7 +564,9 @@ class Net_SSH2 {
|
||||
$this->disconnect_reasons,
|
||||
$this->channel_open_failure_reasons,
|
||||
$this->terminal_modes,
|
||||
$this->channel_extended_data_type_codes
|
||||
$this->channel_extended_data_type_codes,
|
||||
array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
|
||||
array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK')
|
||||
);
|
||||
|
||||
$this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
|
||||
@ -625,12 +645,10 @@ class Net_SSH2 {
|
||||
);
|
||||
|
||||
static $encryption_algorithms = array(
|
||||
'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
|
||||
'aes128-cbc', // RECOMMENDED AES with a 128-bit key
|
||||
'aes192-cbc', // OPTIONAL AES with a 192-bit key
|
||||
'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
|
||||
|
||||
'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
|
||||
|
||||
'3des-cbc', // REQUIRED three-key 3DES in CBC mode
|
||||
'none' // OPTIONAL no encryption; NOT RECOMMENDED
|
||||
);
|
||||
@ -956,6 +974,23 @@ class Net_SSH2 {
|
||||
$n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
||||
$nLength = $temp['length'];
|
||||
|
||||
/*
|
||||
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
|
||||
$signature = $this->_string_shift($signature, $temp['length']);
|
||||
|
||||
if (!class_exists('Crypt_RSA')) {
|
||||
require_once('Crypt/RSA.php');
|
||||
}
|
||||
|
||||
$rsa = new Crypt_RSA();
|
||||
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
|
||||
$rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
|
||||
if (!$rsa->verify($source, $signature)) {
|
||||
user_error('Bad server signature', E_USER_NOTICE);
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
}
|
||||
*/
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
|
||||
$s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256);
|
||||
|
||||
@ -1179,7 +1214,7 @@ class Net_SSH2 {
|
||||
* @return Boolean
|
||||
* @access public
|
||||
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
|
||||
by sending dummy SSH_MSG_IGNORE messages.
|
||||
* by sending dummy SSH_MSG_IGNORE messages.
|
||||
*/
|
||||
function login($username, $password = '')
|
||||
{
|
||||
@ -1208,7 +1243,11 @@ class Net_SSH2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// publickey authentication is required, per the SSH-2 specs, however, we don't support it.
|
||||
// although PHP5's get_class() preserves the case, PHP4's does not
|
||||
if (strtolower(get_class($password)) == 'crypt_rsa') {
|
||||
return $this->_privatekey_login($username, $password);
|
||||
}
|
||||
|
||||
$utf8_password = utf8_encode($password);
|
||||
$packet = pack('CNa*Na*Na*CNa*',
|
||||
NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
|
||||
@ -1238,13 +1277,100 @@ class Net_SSH2 {
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed
|
||||
if (defined('NET_SSH2_LOGGING')) {
|
||||
$this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$this->debug_info.= "\r\n\r\nSSH_MSG_USERAUTH_PASSWD_CHANGEREQ:\r\n" . utf8_decode($this->_string_shift($response, $length));
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
|
||||
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
// either the login is bad or the server employees multi-factor authentication
|
||||
return false;
|
||||
case NET_SSH2_MSG_USERAUTH_SUCCESS:
|
||||
$this->bitmap |= NET_SSH2_MASK_LOGIN;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login with an RSA private key
|
||||
*
|
||||
* @param String $username
|
||||
* @param Crypt_RSA $password
|
||||
* @return Boolean
|
||||
* @access private
|
||||
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
|
||||
* by sending dummy SSH_MSG_IGNORE messages.
|
||||
*/
|
||||
function _privatekey_login($username, $privatekey)
|
||||
{
|
||||
// see http://tools.ietf.org/html/rfc4253#page-15
|
||||
$publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW);
|
||||
$publickey = array(
|
||||
'e' => $publickey['e']->toBytes(true),
|
||||
'n' => $publickey['n']->toBytes(true)
|
||||
);
|
||||
$publickey = pack('Na*Na*Na*',
|
||||
strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey['e']), $publickey['e'], strlen($publickey['n']), $publickey['n']
|
||||
);
|
||||
|
||||
$part1 = pack('CNa*Na*Na*',
|
||||
NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
|
||||
strlen('publickey'), 'publickey'
|
||||
);
|
||||
$part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey);
|
||||
|
||||
$packet = $part1 . chr(0) . $part2;
|
||||
|
||||
if (!$this->_send_binary_packet($packet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server', E_USER_NOTICE);
|
||||
return false;
|
||||
}
|
||||
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$this->debug_info.= "\r\n\r\nSSH_MSG_USERAUTH_FAILURE:\r\n" . $this->_string_shift($response, $length);
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
|
||||
case NET_SSH2_MSG_USERAUTH_PK_OK:
|
||||
// we'll just take it on faith that the public key blob and the public key algorithm name are as
|
||||
// they should be
|
||||
if (defined('NET_SSH2_LOGGING')) {
|
||||
$this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PK_OK';
|
||||
}
|
||||
}
|
||||
|
||||
$packet = $part1 . chr(1) . $part2;
|
||||
$privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
|
||||
$signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
|
||||
$signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature);
|
||||
$packet.= pack('Na*', strlen($signature), $signature);
|
||||
|
||||
if (!$this->_send_binary_packet($packet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server', E_USER_NOTICE);
|
||||
return false;
|
||||
}
|
||||
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
// either the login is bad or the server employees multi-factor authentication
|
||||
return false;
|
||||
case NET_SSH2_MSG_USERAUTH_SUCCESS:
|
||||
$this->bitmap |= NET_SSH2_MASK_LOGIN;
|
||||
return true;
|
||||
@ -1458,7 +1584,8 @@ class Net_SSH2 {
|
||||
$this->get_seq_no++;
|
||||
|
||||
if (defined('NET_SSH2_LOGGING')) {
|
||||
$this->message_number_log[] = '<- ' . $this->message_numbers[ord($payload[0])] .
|
||||
$temp = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN';
|
||||
$this->message_number_log[] = '<- ' . $temp .
|
||||
' (' . round($stop - $start, 4) . 's)';
|
||||
$this->message_log[] = $payload;
|
||||
}
|
||||
@ -1670,7 +1797,8 @@ class Net_SSH2 {
|
||||
$stop = strtok(microtime(), ' ') + strtok('');
|
||||
|
||||
if (defined('NET_SSH2_LOGGING')) {
|
||||
$this->message_number_log[] = '-> ' . $this->message_numbers[ord($data[0])] .
|
||||
$temp = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN';
|
||||
$this->message_number_log[] = '-> ' . $temp .
|
||||
' (' . round($stop - $start, 4) . 's)';
|
||||
$this->message_log[] = $data;
|
||||
}
|
||||
|
59
phpseclib/PHP/Compat/Function/str_split.php
Normal file
59
phpseclib/PHP/Compat/Function/str_split.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* Replace str_split()
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_Compat
|
||||
* @license LGPL - http://www.gnu.org/licenses/lgpl.html
|
||||
* @copyright 2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
|
||||
* @link http://php.net/function.str_split
|
||||
* @author Aidan Lister <aidan@php.net>
|
||||
* @version $Revision: 1.1 $
|
||||
* @since PHP 5
|
||||
* @require PHP 4.0.0 (user_error)
|
||||
*/
|
||||
function php_compat_str_split($string, $split_length = 1)
|
||||
{
|
||||
if (!is_scalar($split_length)) {
|
||||
user_error('str_split() expects parameter 2 to be long, ' .
|
||||
gettype($split_length) . ' given', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
$split_length = (int) $split_length;
|
||||
if ($split_length < 1) {
|
||||
user_error('str_split() The length of each segment must be greater than zero', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select split method
|
||||
if ($split_length < 65536) {
|
||||
// Faster, but only works for less than 2^16
|
||||
preg_match_all('/.{1,' . $split_length . '}/s', $string, $matches);
|
||||
return $matches[0];
|
||||
} else {
|
||||
// Required due to preg limitations
|
||||
$arr = array();
|
||||
$idx = 0;
|
||||
$pos = 0;
|
||||
$len = strlen($string);
|
||||
|
||||
while ($len > 0) {
|
||||
$blk = ($len < $split_length) ? $len : $split_length;
|
||||
$arr[$idx++] = substr($string, $pos, $blk);
|
||||
$pos += $blk;
|
||||
$len -= $blk;
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Define
|
||||
if (!function_exists('str_split')) {
|
||||
function str_split($string, $split_length = 1)
|
||||
{
|
||||
return php_compat_str_split($string, $split_length);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user