diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7664704 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.bak \ No newline at end of file diff --git a/composer.json b/composer.json index a187ad9..de9a023 100644 --- a/composer.json +++ b/composer.json @@ -7,5 +7,9 @@ "email": "phedor@edu.yar.ru" } ], - "require": {} + "autoload": { + "psr-0": { + "": "src/" + } + } } diff --git a/core/connection/all.php b/core/connection/all.php deleted file mode 100644 index 3bc9748..0000000 --- a/core/connection/all.php +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/core/connection/idna_convert.php b/core/connection/idna_convert.php deleted file mode 100644 index 6d5acbe..0000000 --- a/core/connection/idna_convert.php +++ /dev/null @@ -1,2707 +0,0 @@ - - * @author Leonid Kogan - * @copyright 2004-2009 phlyLabs Berlin, http://phlylabs.de - * @version 0.6.3 - * @changelog since 0.5.1 class updated to PHP5/6 style should be compatible to PHP 4.3+ - * - added a missing replace mapping for THAI CHARACTER SARA AM - */ -class idna_convert -{ - // NP See below - - // Internal settings, do not mess with them - private $_punycode_prefix = 'xn--'; - private $_invalid_ucs = 0x80000000; - private $_max_ucs = 0x10FFFF; - private $_base = 36; - private $_tmin = 1; - private $_tmax = 26; - private $_skew = 38; - private $_damp = 700; - private $_initial_bias = 72; - private $_initial_n = 0x80; - private $_sbase = 0xAC00; - private $_lbase = 0x1100; - private $_vbase = 0x1161; - private $_tbase = 0x11A7; - private $_lcount = 19; - private $_vcount = 21; - private $_tcount = 28; - private $_ncount = 588; // _vcount * _tcount - private $_scount = 11172; // _lcount * _tcount * _vcount - private $_error = false; - - // See {@link set_paramter()} for details of how to change the following - // settings from within your script / application - private $_api_encoding = 'utf8'; // Default input charset is UTF-8 - private $_allow_overlong = false; // Overlong UTF-8 encodings are forbidden - private $_strict_mode = false; // Behave strict or not - - - /** - * the constructor - * - * @param array $options - * @return boolean - * @since 0.5.2 - */ - public function __construct($options = false) - { - $this->slast = $this->_sbase + $this->_lcount * $this->_vcount * $this->_tcount; - // If parameters are given, pass these to the respective method - if (is_array($options)) return $this->set_parameter($options); - return true; - } - - /** - * Sets a new option value. Available options and values: - * [encoding - Use either UTF-8, UCS4 as array or UCS4 as string as input ('utf8' for UTF-8, - * 'ucs4_string' and 'ucs4_array' respectively for UCS4); The output is always UTF-8] - * [overlong - Unicode does not allow unnecessarily long encodings of chars, - * to allow this, set this parameter to true, else to false; - * default is false.] - * [strict - true: strict mode, good for registration purposes - Causes errors - * on failures; false: loose mode, ideal for "wildlife" applications - * by silently ignoring errors and returning the original input instead - * - * @param mixed Parameter to set (string: single parameter; array of Parameter => Value pairs) - * @param string Value to use (if parameter 1 is a string) - * @return boolean true on success, false otherwise - */ - public function set_parameter($option, $value = false) - { - if (!is_array($option)) { - $option = array($option => $value); - } - foreach ($option as $k => $v) { - switch ($k) { - case 'encoding': - switch ($v) { - case 'utf8': - case 'ucs4_string': - case 'ucs4_array': - $this->_api_encoding = $v; - break; - default: - $this->_error('Set Parameter: Unknown parameter '.$v.' for option '.$k); - return false; - } - break; - case 'overlong': - $this->_allow_overlong = ($v) ? true : false; - break; - case 'strict': - $this->_strict_mode = ($v) ? true : false; - break; - default: - $this->_error('Set Parameter: Unknown option '.$k); - return false; - } - } - return true; - } - - /** - * Decode a given ACE domain name - * @param string Domain name (ACE string) - * [@param string Desired output encoding, see {@link set_parameter}] - * @return string Decoded Domain name (UTF-8 or UCS-4) - */ - public function decode($input, $one_time_encoding = false) - { - // Optionally set - if ($one_time_encoding) { - switch ($one_time_encoding) { - case 'utf8': - case 'ucs4_string': - case 'ucs4_array': - break; - default: - $this->_error('Unknown encoding '.$one_time_encoding); - return false; - } - } - // Make sure to drop any newline characters around - $input = trim($input); - - // Negotiate input and try to determine, whether it is a plain string, - // an email address or something like a complete URL - if (strpos($input, '@')) { // Maybe it is an email address - // No no in strict mode - if ($this->_strict_mode) { - $this->_error('Only simple domain name parts can be handled in strict mode'); - return false; - } - list ($email_pref, $input) = explode('@', $input, 2); - $arr = explode('.', $input); - foreach ($arr as $k => $v) { - if (preg_match('!^'.preg_quote($this->_punycode_prefix, '!').'!', $v)) { - $conv = $this->_decode($v); - if ($conv) $arr[$k] = $conv; - } - } - $input = join('.', $arr); - $arr = explode('.', $email_pref); - foreach ($arr as $k => $v) { - if (preg_match('!^'.preg_quote($this->_punycode_prefix, '!').'!', $v)) { - $conv = $this->_decode($v); - if ($conv) $arr[$k] = $conv; - } - } - $email_pref = join('.', $arr); - $return = $email_pref . '@' . $input; - } elseif (preg_match('![:\./]!', $input)) { // Or a complete domain name (with or without paths / parameters) - // No no in strict mode - if ($this->_strict_mode) { - $this->_error('Only simple domain name parts can be handled in strict mode'); - return false; - } - $parsed = parse_url($input); - if (isset($parsed['host'])) { - $arr = explode('.', $parsed['host']); - foreach ($arr as $k => $v) { - $conv = $this->_decode($v); - if ($conv) $arr[$k] = $conv; - } - $parsed['host'] = join('.', $arr); - $return = - (empty($parsed['scheme']) ? '' : $parsed['scheme'].(strtolower($parsed['scheme']) == 'mailto' ? ':' : '://')) - .(empty($parsed['user']) ? '' : $parsed['user'].(empty($parsed['pass']) ? '' : ':'.$parsed['pass']).'@') - .$parsed['host'] - .(empty($parsed['port']) ? '' : ':'.$parsed['port']) - .(empty($parsed['path']) ? '' : $parsed['path']) - .(empty($parsed['query']) ? '' : '?'.$parsed['query']) - .(empty($parsed['fragment']) ? '' : '#'.$parsed['fragment']); - } else { // parse_url seems to have failed, try without it - $arr = explode('.', $input); - foreach ($arr as $k => $v) { - $conv = $this->_decode($v); - $arr[$k] = ($conv) ? $conv : $v; - } - $return = join('.', $arr); - } - } else { // Otherwise we consider it being a pure domain name string - $return = $this->_decode($input); - if (!$return) $return = $input; - } - // The output is UTF-8 by default, other output formats need conversion here - // If one time encoding is given, use this, else the objects property - switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) { - case 'utf8': - return $return; - break; - case 'ucs4_string': - return $this->_ucs4_to_ucs4_string($this->_utf8_to_ucs4($return)); - break; - case 'ucs4_array': - return $this->_utf8_to_ucs4($return); - break; - default: - $this->_error('Unsupported output format'); - return false; - } - } - - /** - * Encode a given UTF-8 domain name - * @param string Domain name (UTF-8 or UCS-4) - * [@param string Desired input encoding, see {@link set_parameter}] - * @return string Encoded Domain name (ACE string) - */ - public function encode($decoded, $one_time_encoding = false) - { - // Forcing conversion of input to UCS4 array - // If one time encoding is given, use this, else the objects property - switch ($one_time_encoding ? $one_time_encoding : $this->_api_encoding) { - case 'utf8': - $decoded = $this->_utf8_to_ucs4($decoded); - break; - case 'ucs4_string': - $decoded = $this->_ucs4_string_to_ucs4($decoded); - case 'ucs4_array': - break; - default: - $this->_error('Unsupported input format: '.($one_time_encoding ? $one_time_encoding : $this->_api_encoding)); - return false; - } - - // No input, no output, what else did you expect? - if (empty($decoded)) return ''; - - // Anchors for iteration - $last_begin = 0; - // Output string - $output = ''; - foreach ($decoded as $k => $v) { - // Make sure to use just the plain dot - switch($v) { - case 0x3002: - case 0xFF0E: - case 0xFF61: - $decoded[$k] = 0x2E; - // Right, no break here, the above are converted to dots anyway - // Stumbling across an anchoring character - case 0x2E: - case 0x2F: - case 0x3A: - case 0x3F: - case 0x40: - // Neither email addresses nor URLs allowed in strict mode - if ($this->_strict_mode) { - $this->_error('Neither email addresses nor URLs are allowed in strict mode.'); - return false; - } else { - // Skip first char - if ($k) { - $encoded = ''; - $encoded = $this->_encode(array_slice($decoded, $last_begin, (($k)-$last_begin))); - if ($encoded) { - $output .= $encoded; - } else { - $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($k)-$last_begin))); - } - $output .= chr($decoded[$k]); - } - $last_begin = $k + 1; - } - } - } - // Catch the rest of the string - if ($last_begin) { - $inp_len = sizeof($decoded); - $encoded = ''; - $encoded = $this->_encode(array_slice($decoded, $last_begin, (($inp_len)-$last_begin))); - if ($encoded) { - $output .= $encoded; - } else { - $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($inp_len)-$last_begin))); - } - return $output; - } else { - if ($output = $this->_encode($decoded)) { - return $output; - } else { - return $this->_ucs4_to_utf8($decoded); - } - } - } - - /** - * Use this method to get the last error ocurred - * @param void - * @return string The last error, that occured - */ - public function get_last_error() - { - return $this->_error; - } - - /** - * The actual decoding algorithm - * @param string - * @return mixed - */ - private function _decode($encoded) - { - $decoded = array(); - // find the Punycode prefix - if (!preg_match('!^'.preg_quote($this->_punycode_prefix, '!').'!', $encoded)) { - $this->_error('This is not a punycode string'); - return false; - } - $encode_test = preg_replace('!^'.preg_quote($this->_punycode_prefix, '!').'!', '', $encoded); - // If nothing left after removing the prefix, it is hopeless - if (!$encode_test) { - $this->_error('The given encoded string was empty'); - return false; - } - // Find last occurence of the delimiter - $delim_pos = strrpos($encoded, '-'); - if ($delim_pos > strlen($this->_punycode_prefix)) { - for ($k = strlen($this->_punycode_prefix); $k < $delim_pos; ++$k) { - $decoded[] = ord($encoded{$k}); - } - } - $deco_len = count($decoded); - $enco_len = strlen($encoded); - - // Wandering through the strings; init - $is_first = true; - $bias = $this->_initial_bias; - $idx = 0; - $char = $this->_initial_n; - - for ($enco_idx = ($delim_pos) ? ($delim_pos + 1) : 0; $enco_idx < $enco_len; ++$deco_len) { - for ($old_idx = $idx, $w = 1, $k = $this->_base; 1 ; $k += $this->_base) { - $digit = $this->_decode_digit($encoded{$enco_idx++}); - $idx += $digit * $w; - $t = ($k <= $bias) ? $this->_tmin : - (($k >= $bias + $this->_tmax) ? $this->_tmax : ($k - $bias)); - if ($digit < $t) break; - $w = (int) ($w * ($this->_base - $t)); - } - $bias = $this->_adapt($idx - $old_idx, $deco_len + 1, $is_first); - $is_first = false; - $char += (int) ($idx / ($deco_len + 1)); - $idx %= ($deco_len + 1); - if ($deco_len > 0) { - // Make room for the decoded char - for ($i = $deco_len; $i > $idx; $i--) $decoded[$i] = $decoded[($i - 1)]; - } - $decoded[$idx++] = $char; - } - return $this->_ucs4_to_utf8($decoded); - } - - /** - * The actual encoding algorithm - * @param string - * @return mixed - */ - private function _encode($decoded) - { - // We cannot encode a domain name containing the Punycode prefix - $extract = strlen($this->_punycode_prefix); - $check_pref = $this->_utf8_to_ucs4($this->_punycode_prefix); - $check_deco = array_slice($decoded, 0, $extract); - - if ($check_pref == $check_deco) { - $this->_error('This is already a punycode string'); - return false; - } - // We will not try to encode strings consisting of basic code points only - $encodable = false; - foreach ($decoded as $k => $v) { - if ($v > 0x7a) { - $encodable = true; - break; - } - } - if (!$encodable) { - $this->_error('The given string does not contain encodable chars'); - return false; - } - // Do NAMEPREP - $decoded = $this->_nameprep($decoded); - if (!$decoded || !is_array($decoded)) return false; // NAMEPREP failed - $deco_len = count($decoded); - if (!$deco_len) return false; // Empty array - $codecount = 0; // How many chars have been consumed - $encoded = ''; - // Copy all basic code points to output - for ($i = 0; $i < $deco_len; ++$i) { - $test = $decoded[$i]; - // Will match [-0-9a-zA-Z] - if ((0x2F < $test && $test < 0x40) || (0x40 < $test && $test < 0x5B) - || (0x60 < $test && $test <= 0x7B) || (0x2D == $test)) { - $encoded .= chr($decoded[$i]); - $codecount++; - } - } - if ($codecount == $deco_len) return $encoded; // All codepoints were basic ones - - // Start with the prefix; copy it to output - $encoded = $this->_punycode_prefix.$encoded; - // If we have basic code points in output, add an hyphen to the end - if ($codecount) $encoded .= '-'; - // Now find and encode all non-basic code points - $is_first = true; - $cur_code = $this->_initial_n; - $bias = $this->_initial_bias; - $delta = 0; - while ($codecount < $deco_len) { - // Find the smallest code point >= the current code point and - // remember the last ouccrence of it in the input - for ($i = 0, $next_code = $this->_max_ucs; $i < $deco_len; $i++) { - if ($decoded[$i] >= $cur_code && $decoded[$i] <= $next_code) { - $next_code = $decoded[$i]; - } - } - $delta += ($next_code - $cur_code) * ($codecount + 1); - $cur_code = $next_code; - - // Scan input again and encode all characters whose code point is $cur_code - for ($i = 0; $i < $deco_len; $i++) { - if ($decoded[$i] < $cur_code) { - $delta++; - } elseif ($decoded[$i] == $cur_code) { - for ($q = $delta, $k = $this->_base; 1; $k += $this->_base) { - $t = ($k <= $bias) ? $this->_tmin : - (($k >= $bias + $this->_tmax) ? $this->_tmax : $k - $bias); - if ($q < $t) break; - $encoded .= $this->_encode_digit(intval($t + (($q - $t) % ($this->_base - $t)))); //v0.4.5 Changed from ceil() to intval() - $q = (int) (($q - $t) / ($this->_base - $t)); - } - $encoded .= $this->_encode_digit($q); - $bias = $this->_adapt($delta, $codecount+1, $is_first); - $codecount++; - $delta = 0; - $is_first = false; - } - } - $delta++; - $cur_code++; - } - return $encoded; - } - - /** - * Adapt the bias according to the current code point and position - * @param int $delta - * @param int $npoints - * @param int $is_first - * @return int - */ - private function _adapt($delta, $npoints, $is_first) - { - $delta = intval($is_first ? ($delta / $this->_damp) : ($delta / 2)); - $delta += intval($delta / $npoints); - for ($k = 0; $delta > (($this->_base - $this->_tmin) * $this->_tmax) / 2; $k += $this->_base) { - $delta = intval($delta / ($this->_base - $this->_tmin)); - } - return intval($k + ($this->_base - $this->_tmin + 1) * $delta / ($delta + $this->_skew)); - } - - /** - * Encoding a certain digit - * @param int $d - * @return string - */ - private function _encode_digit($d) - { - return chr($d + 22 + 75 * ($d < 26)); - } - - /** - * Decode a certain digit - * @param int $cp - * @return int - */ - private function _decode_digit($cp) - { - $cp = ord($cp); - return ($cp - 48 < 10) ? $cp - 22 : (($cp - 65 < 26) ? $cp - 65 : (($cp - 97 < 26) ? $cp - 97 : $this->_base)); - } - - /** - * Internal error handling method - * @param string $error - */ - private function _error($error = '') - { - $this->_error = $error; - } - - /** - * Do Nameprep according to RFC3491 and RFC3454 - * @param array Unicode Characters - * @return string Unicode Characters, Nameprep'd - */ - private function _nameprep($input) - { - $output = array(); - $error = false; - // - // Mapping - // Walking through the input array, performing the required steps on each of - // the input chars and putting the result into the output array - // While mapping required chars we apply the cannonical ordering - foreach ($input as $v) { - // Map to nothing == skip that code point - if (in_array($v, $this->NP['map_nothing'])) continue; - // Try to find prohibited input - if (in_array($v, $this->NP['prohibit']) || in_array($v, $this->NP['general_prohibited'])) { - $this->_error('NAMEPREP: Prohibited input U+'.sprintf('%08X', $v)); - return false; - } - foreach ($this->NP['prohibit_ranges'] as $range) { - if ($range[0] <= $v && $v <= $range[1]) { - $this->_error('NAMEPREP: Prohibited input U+'.sprintf('%08X', $v)); - return false; - } - } - // Hangul syllable decomposition - if (0xAC00 <= $v && $v <= 0xD7AF) { - foreach ($this->_hangul_decompose($v) as $out) $output[] = (int) $out; - // There's a decomposition mapping for that code point - } elseif (isset($this->NP['replacemaps'][$v])) { - foreach ($this->_apply_cannonical_ordering($this->NP['replacemaps'][$v]) as $out) { - $output[] = (int) $out; - } - } else { - $output[] = (int) $v; - } - } - // Before applying any Combining, try to rearrange any Hangul syllables - $output = $this->_hangul_compose($output); - // - // Combine code points - // - $last_class = 0; - $last_starter = 0; - $out_len = count($output); - for ($i = 0; $i < $out_len; ++$i) { - $class = $this->_get_combining_class($output[$i]); - if ((!$last_class || $last_class > $class) && $class) { - // Try to match - $seq_len = $i - $last_starter; - $out = $this->_combine(array_slice($output, $last_starter, $seq_len)); - // On match: Replace the last starter with the composed character and remove - // the now redundant non-starter(s) - if ($out) { - $output[$last_starter] = $out; - if (count($out) != $seq_len) { - for ($j = $i+1; $j < $out_len; ++$j) $output[$j-1] = $output[$j]; - unset($output[$out_len]); - } - // Rewind the for loop by one, since there can be more possible compositions - $i--; - $out_len--; - $last_class = ($i == $last_starter) ? 0 : $this->_get_combining_class($output[$i-1]); - continue; - } - } - // The current class is 0 - if (!$class) $last_starter = $i; - $last_class = $class; - } - return $output; - } - - /** - * Decomposes a Hangul syllable - * (see http://www.unicode.org/unicode/reports/tr15/#Hangul - * @param integer 32bit UCS4 code point - * @return array Either Hangul Syllable decomposed or original 32bit value as one value array - */ - private function _hangul_decompose($char) - { - $sindex = (int) $char - $this->_sbase; - if ($sindex < 0 || $sindex >= $this->_scount) return array($char); - $result = array(); - $result[] = (int) $this->_lbase + $sindex / $this->_ncount; - $result[] = (int) $this->_vbase + ($sindex % $this->_ncount) / $this->_tcount; - $T = intval($this->_tbase + $sindex % $this->_tcount); - if ($T != $this->_tbase) $result[] = $T; - return $result; - } - /** - * Ccomposes a Hangul syllable - * (see http://www.unicode.org/unicode/reports/tr15/#Hangul - * @param array Decomposed UCS4 sequence - * @return array UCS4 sequence with syllables composed - */ - private function _hangul_compose($input) - { - $inp_len = count($input); - if (!$inp_len) return array(); - $result = array(); - $last = (int) $input[0]; - $result[] = $last; // copy first char from input to output - - for ($i = 1; $i < $inp_len; ++$i) { - $char = (int) $input[$i]; - $sindex = $last - $this->_sbase; - $lindex = $last - $this->_lbase; - $vindex = $char - $this->_vbase; - $tindex = $char - $this->_tbase; - // Find out, whether two current characters are LV and T - if (0 <= $sindex && $sindex < $this->_scount && ($sindex % $this->_tcount == 0) - && 0 <= $tindex && $tindex <= $this->_tcount) { - // create syllable of form LVT - $last += $tindex; - $result[(count($result) - 1)] = $last; // reset last - continue; // discard char - } - // Find out, whether two current characters form L and V - if (0 <= $lindex && $lindex < $this->_lcount && 0 <= $vindex && $vindex < $this->_vcount) { - // create syllable of form LV - $last = (int) $this->_sbase + ($lindex * $this->_vcount + $vindex) * $this->_tcount; - $result[(count($result) - 1)] = $last; // reset last - continue; // discard char - } - // if neither case was true, just add the character - $last = $char; - $result[] = $char; - } - return $result; - } - - /** - * Returns the combining class of a certain wide char - * @param integer Wide char to check (32bit integer) - * @return integer Combining class if found, else 0 - */ - private function _get_combining_class($char) - { - return isset($this->NP['norm_combcls'][$char]) ? $this->NP['norm_combcls'][$char] : 0; - } - - /** - * Apllies the cannonical ordering of a decomposed UCS4 sequence - * @param array Decomposed UCS4 sequence - * @return array Ordered USC4 sequence - */ - private function _apply_cannonical_ordering($input) - { - $swap = true; - $size = count($input); - while ($swap) { - $swap = false; - $last = $this->_get_combining_class(intval($input[0])); - for ($i = 0; $i < $size-1; ++$i) { - $next = $this->_get_combining_class(intval($input[$i+1])); - if ($next != 0 && $last > $next) { - // Move item leftward until it fits - for ($j = $i + 1; $j > 0; --$j) { - if ($this->_get_combining_class(intval($input[$j-1])) <= $next) break; - $t = intval($input[$j]); - $input[$j] = intval($input[$j-1]); - $input[$j-1] = $t; - $swap = true; - } - // Reentering the loop looking at the old character again - $next = $last; - } - $last = $next; - } - } - return $input; - } - - /** - * Do composition of a sequence of starter and non-starter - * @param array UCS4 Decomposed sequence - * @return array Ordered USC4 sequence - */ - private function _combine($input) - { - $inp_len = count($input); - foreach ($this->NP['replacemaps'] as $np_src => $np_target) { - if ($np_target[0] != $input[0]) continue; - if (count($np_target) != $inp_len) continue; - $hit = false; - foreach ($input as $k2 => $v2) { - if ($v2 == $np_target[$k2]) { - $hit = true; - } else { - $hit = false; - break; - } - } - if ($hit) return $np_src; - } - return false; - } - - /** - * This converts an UTF-8 encoded string to its UCS-4 representation - * By talking about UCS-4 "strings" we mean arrays of 32bit integers representing - * each of the "chars". This is due to PHP not being able to handle strings with - * bit depth different from 8. This apllies to the reverse method _ucs4_to_utf8(), too. - * The following UTF-8 encodings are supported: - * bytes bits representation - * 1 7 0xxxxxxx - * 2 11 110xxxxx 10xxxxxx - * 3 16 1110xxxx 10xxxxxx 10xxxxxx - * 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * 5 26 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * 6 31 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * Each x represents a bit that can be used to store character data. - * The five and six byte sequences are part of Annex D of ISO/IEC 10646-1:2000 - * @param string $input - * @return string - */ - private function _utf8_to_ucs4($input) - { - $output = array(); - $out_len = 0; - // Patch by Daniel Hahler; work around prolbem with mbstring.func_overload - if (function_exists('mb_strlen')) { - $inp_len = mb_strlen($input, '8bit'); - } else { - $inp_len = strlen($input); - } - $mode = 'next'; - $test = 'none'; - for ($k = 0; $k < $inp_len; ++$k) { - $v = ord($input{$k}); // Extract byte from input string - if ($v < 128) { // We found an ASCII char - put into stirng as is - $output[$out_len] = $v; - ++$out_len; - if ('add' == $mode) { - $this->_error('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k); - return false; - } - continue; - } - if ('next' == $mode) { // Try to find the next start byte; determine the width of the Unicode char - $start_byte = $v; - $mode = 'add'; - $test = 'range'; - if ($v >> 5 == 6) { // &110xxxxx 10xxxxx - $next_byte = 0; // Tells, how many times subsequent bitmasks must rotate 6bits to the left - $v = ($v - 192) << 6; - } elseif ($v >> 4 == 14) { // &1110xxxx 10xxxxxx 10xxxxxx - $next_byte = 1; - $v = ($v - 224) << 12; - } elseif ($v >> 3 == 30) { // &11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - $next_byte = 2; - $v = ($v - 240) << 18; - } elseif ($v >> 2 == 62) { // &111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - $next_byte = 3; - $v = ($v - 248) << 24; - } elseif ($v >> 1 == 126) { // &1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - $next_byte = 4; - $v = ($v - 252) << 30; - } else { - $this->_error('This might be UTF-8, but I don\'t understand it at byte '.$k); - return false; - } - if ('add' == $mode) { - $output[$out_len] = (int) $v; - ++$out_len; - continue; - } - } - if ('add' == $mode) { - if (!$this->_allow_overlong && $test == 'range') { - $test = 'none'; - if (($v < 0xA0 && $start_byte == 0xE0) || ($v < 0x90 && $start_byte == 0xF0) || ($v > 0x8F && $start_byte == 0xF4)) { - $this->_error('Bogus UTF-8 character detected (out of legal range) at byte '.$k); - return false; - } - } - if ($v >> 6 == 2) { // Bit mask must be 10xxxxxx - $v = ($v - 128) << ($next_byte * 6); - $output[($out_len - 1)] += $v; - --$next_byte; - } else { - $this->_error('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k); - return false; - } - if ($next_byte < 0) { - $mode = 'next'; - } - } - } // for - return $output; - } - - /** - * Convert UCS-4 string into UTF-8 string - * See _utf8_to_ucs4() for details - * @param string $input - * @return string - */ - private function _ucs4_to_utf8($input) - { - $output = ''; - foreach ($input as $k => $v) { - if ($v < 128) { // 7bit are transferred literally - $output .= chr($v); - } elseif ($v < (1 << 11)) { // 2 bytes - $output .= chr(192+($v >> 6)).chr(128+($v & 63)); - } elseif ($v < (1 << 16)) { // 3 bytes - $output .= chr(224+($v >> 12)).chr(128+(($v >> 6) & 63)).chr(128+($v & 63)); - } elseif ($v < (1 << 21)) { // 4 bytes - $output .= chr(240+($v >> 18)).chr(128+(($v >> 12) & 63)).chr(128+(($v >> 6) & 63)).chr(128+($v & 63)); - } elseif (self::$safe_mode) { - $output .= self::$safe_char; - } else { - $this->_error('Conversion from UCS-4 to UTF-8 failed: malformed input at byte '.$k); - return false; - } - } - return $output; - } - - /** - * Convert UCS-4 array into UCS-4 string - * - * @param array $input - * @return string - */ - private function _ucs4_to_ucs4_string($input) - { - $output = ''; - // Take array values and split output to 4 bytes per value - // The bit mask is 255, which reads &11111111 - foreach ($input as $v) { - $output .= chr(($v >> 24) & 255).chr(($v >> 16) & 255).chr(($v >> 8) & 255).chr($v & 255); - } - return $output; - } - - /** - * Convert UCS-4 strin into UCS-4 garray - * - * @param string $input - * @return array - */ - private function _ucs4_string_to_ucs4($input) - { - $output = array(); - $inp_len = strlen($input); - // Input length must be dividable by 4 - if ($inp_len % 4) { - $this->_error('Input UCS4 string is broken'); - return false; - } - // Empty input - return empty output - if (!$inp_len) return $output; - for ($i = 0, $out_len = -1; $i < $inp_len; ++$i) { - // Increment output position every 4 input bytes - if (!($i % 4)) { - $out_len++; - $output[$out_len] = 0; - } - $output[$out_len] += ord($input{$i}) << (8 * (3 - ($i % 4) ) ); - } - return $output; - } - - /** - * Holds all relevant mapping tables, loaded from a seperate file on construct - * See RFC3454 for details - * - * @private array - * @since 0.5.2 - * - */ - private $NP = array - ('map_nothing' => array - (0xAD, 0x34F, 0x1806, 0x180B, 0x180C, 0x180D, 0x200B - ,0x200C, 0x200D, 0x2060, 0xFE00, 0xFE01, 0xFE02, 0xFE03 - ,0xFE04, 0xFE05, 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A - ,0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F, 0xFEFF - ) - ,'general_prohibited' => array - (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE - ,0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 - ,0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20 - ,0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29 - ,0x2A, 0x2B, 0x2C, 0x2F, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F - ,0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x7B, 0x7C - ,0x7D, 0x7E, 0x7F, 0x3002 - ) - ,'prohibit' => array - (0xA0, 0x340, 0x341, 0x6DD, 0x70F, 0x1680, 0x180E, 0x2000 - ,0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007 - ,0x2008, 0x2009, 0x200A, 0x200B, 0x200C, 0x200D, 0x200E - ,0x200F, 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D - ,0x202E, 0x202F, 0x205F, 0x206A, 0x206B, 0x206C, 0x206D - ,0x206E, 0x206F, 0x3000, 0xFEFF, 0xFFF9, 0xFFFA, 0xFFFB - ,0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF, 0x1FFFE, 0x1FFFF, 0x2FFFE - ,0x2FFFF, 0x3FFFE, 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE - ,0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE, 0x7FFFF, 0x8FFFE - ,0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF, 0xBFFFE - ,0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE, 0xDFFFF, 0xE0001 - ,0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, 0x10FFFE, 0x10FFFF - ) - ,'prohibit_ranges' => array - (array(0x80, 0x9F), array(0x2060, 0x206F) - ,array(0x1D173, 0x1D17A), array(0xE000, 0xF8FF) - ,array(0xF0000, 0xFFFFD), array(0x100000, 0x10FFFD) - ,array(0xFDD0, 0xFDEF), array(0xD800, 0xDFFF) - ,array(0x2FF0, 0x2FFB), array(0xE0020, 0xE007F) - ) - ,'replacemaps' => array - (0x41 => array(0x61) - ,0x42 => array(0x62) - ,0x43 => array(0x63) - ,0x44 => array(0x64) - ,0x45 => array(0x65) - ,0x46 => array(0x66) - ,0x47 => array(0x67) - ,0x48 => array(0x68) - ,0x49 => array(0x69) - ,0x4A => array(0x6A) - ,0x4B => array(0x6B) - ,0x4C => array(0x6C) - ,0x4D => array(0x6D) - ,0x4E => array(0x6E) - ,0x4F => array(0x6F) - ,0x50 => array(0x70) - ,0x51 => array(0x71) - ,0x52 => array(0x72) - ,0x53 => array(0x73) - ,0x54 => array(0x74) - ,0x55 => array(0x75) - ,0x56 => array(0x76) - ,0x57 => array(0x77) - ,0x58 => array(0x78) - ,0x59 => array(0x79) - ,0x5A => array(0x7A) - ,0xB5 => array(0x3BC) - ,0xC0 => array(0xE0) - ,0xC1 => array(0xE1) - ,0xC2 => array(0xE2) - ,0xC3 => array(0xE3) - ,0xC4 => array(0xE4) - ,0xC5 => array(0xE5) - ,0xC6 => array(0xE6) - ,0xC7 => array(0xE7) - ,0xC8 => array(0xE8) - ,0xC9 => array(0xE9) - ,0xCA => array(0xEA) - ,0xCB => array(0xEB) - ,0xCC => array(0xEC) - ,0xCD => array(0xED) - ,0xCE => array(0xEE) - ,0xCF => array(0xEF) - ,0xD0 => array(0xF0) - ,0xD1 => array(0xF1) - ,0xD2 => array(0xF2) - ,0xD3 => array(0xF3) - ,0xD4 => array(0xF4) - ,0xD5 => array(0xF5) - ,0xD6 => array(0xF6) - ,0xD8 => array(0xF8) - ,0xD9 => array(0xF9) - ,0xDA => array(0xFA) - ,0xDB => array(0xFB) - ,0xDC => array(0xFC) - ,0xDD => array(0xFD) - ,0xDE => array(0xFE) - ,0xDF => array(0x73, 0x73) - ,0x100 => array(0x101) - ,0x102 => array(0x103) - ,0x104 => array(0x105) - ,0x106 => array(0x107) - ,0x108 => array(0x109) - ,0x10A => array(0x10B) - ,0x10C => array(0x10D) - ,0x10E => array(0x10F) - ,0x110 => array(0x111) - ,0x112 => array(0x113) - ,0x114 => array(0x115) - ,0x116 => array(0x117) - ,0x118 => array(0x119) - ,0x11A => array(0x11B) - ,0x11C => array(0x11D) - ,0x11E => array(0x11F) - ,0x120 => array(0x121) - ,0x122 => array(0x123) - ,0x124 => array(0x125) - ,0x126 => array(0x127) - ,0x128 => array(0x129) - ,0x12A => array(0x12B) - ,0x12C => array(0x12D) - ,0x12E => array(0x12F) - ,0x130 => array(0x69, 0x307) - ,0x132 => array(0x133) - ,0x134 => array(0x135) - ,0x136 => array(0x137) - ,0x139 => array(0x13A) - ,0x13B => array(0x13C) - ,0x13D => array(0x13E) - ,0x13F => array(0x140) - ,0x141 => array(0x142) - ,0x143 => array(0x144) - ,0x145 => array(0x146) - ,0x147 => array(0x148) - ,0x149 => array(0x2BC, 0x6E) - ,0x14A => array(0x14B) - ,0x14C => array(0x14D) - ,0x14E => array(0x14F) - ,0x150 => array(0x151) - ,0x152 => array(0x153) - ,0x154 => array(0x155) - ,0x156 => array(0x157) - ,0x158 => array(0x159) - ,0x15A => array(0x15B) - ,0x15C => array(0x15D) - ,0x15E => array(0x15F) - ,0x160 => array(0x161) - ,0x162 => array(0x163) - ,0x164 => array(0x165) - ,0x166 => array(0x167) - ,0x168 => array(0x169) - ,0x16A => array(0x16B) - ,0x16C => array(0x16D) - ,0x16E => array(0x16F) - ,0x170 => array(0x171) - ,0x172 => array(0x173) - ,0x174 => array(0x175) - ,0x176 => array(0x177) - ,0x178 => array(0xFF) - ,0x179 => array(0x17A) - ,0x17B => array(0x17C) - ,0x17D => array(0x17E) - ,0x17F => array(0x73) - ,0x181 => array(0x253) - ,0x182 => array(0x183) - ,0x184 => array(0x185) - ,0x186 => array(0x254) - ,0x187 => array(0x188) - ,0x189 => array(0x256) - ,0x18A => array(0x257) - ,0x18B => array(0x18C) - ,0x18E => array(0x1DD) - ,0x18F => array(0x259) - ,0x190 => array(0x25B) - ,0x191 => array(0x192) - ,0x193 => array(0x260) - ,0x194 => array(0x263) - ,0x196 => array(0x269) - ,0x197 => array(0x268) - ,0x198 => array(0x199) - ,0x19C => array(0x26F) - ,0x19D => array(0x272) - ,0x19F => array(0x275) - ,0x1A0 => array(0x1A1) - ,0x1A2 => array(0x1A3) - ,0x1A4 => array(0x1A5) - ,0x1A6 => array(0x280) - ,0x1A7 => array(0x1A8) - ,0x1A9 => array(0x283) - ,0x1AC => array(0x1AD) - ,0x1AE => array(0x288) - ,0x1AF => array(0x1B0) - ,0x1B1 => array(0x28A) - ,0x1B2 => array(0x28B) - ,0x1B3 => array(0x1B4) - ,0x1B5 => array(0x1B6) - ,0x1B7 => array(0x292) - ,0x1B8 => array(0x1B9) - ,0x1BC => array(0x1BD) - ,0x1C4 => array(0x1C6) - ,0x1C5 => array(0x1C6) - ,0x1C7 => array(0x1C9) - ,0x1C8 => array(0x1C9) - ,0x1CA => array(0x1CC) - ,0x1CB => array(0x1CC) - ,0x1CD => array(0x1CE) - ,0x1CF => array(0x1D0) - ,0x1D1 => array(0x1D2) - ,0x1D3 => array(0x1D4) - ,0x1D5 => array(0x1D6) - ,0x1D7 => array(0x1D8) - ,0x1D9 => array(0x1DA) - ,0x1DB => array(0x1DC) - ,0x1DE => array(0x1DF) - ,0x1E0 => array(0x1E1) - ,0x1E2 => array(0x1E3) - ,0x1E4 => array(0x1E5) - ,0x1E6 => array(0x1E7) - ,0x1E8 => array(0x1E9) - ,0x1EA => array(0x1EB) - ,0x1EC => array(0x1ED) - ,0x1EE => array(0x1EF) - ,0x1F0 => array(0x6A, 0x30C) - ,0x1F1 => array(0x1F3) - ,0x1F2 => array(0x1F3) - ,0x1F4 => array(0x1F5) - ,0x1F6 => array(0x195) - ,0x1F7 => array(0x1BF) - ,0x1F8 => array(0x1F9) - ,0x1FA => array(0x1FB) - ,0x1FC => array(0x1FD) - ,0x1FE => array(0x1FF) - ,0x200 => array(0x201) - ,0x202 => array(0x203) - ,0x204 => array(0x205) - ,0x206 => array(0x207) - ,0x208 => array(0x209) - ,0x20A => array(0x20B) - ,0x20C => array(0x20D) - ,0x20E => array(0x20F) - ,0x210 => array(0x211) - ,0x212 => array(0x213) - ,0x214 => array(0x215) - ,0x216 => array(0x217) - ,0x218 => array(0x219) - ,0x21A => array(0x21B) - ,0x21C => array(0x21D) - ,0x21E => array(0x21F) - ,0x220 => array(0x19E) - ,0x222 => array(0x223) - ,0x224 => array(0x225) - ,0x226 => array(0x227) - ,0x228 => array(0x229) - ,0x22A => array(0x22B) - ,0x22C => array(0x22D) - ,0x22E => array(0x22F) - ,0x230 => array(0x231) - ,0x232 => array(0x233) - ,0x345 => array(0x3B9) - ,0x37A => array(0x20, 0x3B9) - ,0x386 => array(0x3AC) - ,0x388 => array(0x3AD) - ,0x389 => array(0x3AE) - ,0x38A => array(0x3AF) - ,0x38C => array(0x3CC) - ,0x38E => array(0x3CD) - ,0x38F => array(0x3CE) - ,0x390 => array(0x3B9, 0x308, 0x301) - ,0x391 => array(0x3B1) - ,0x392 => array(0x3B2) - ,0x393 => array(0x3B3) - ,0x394 => array(0x3B4) - ,0x395 => array(0x3B5) - ,0x396 => array(0x3B6) - ,0x397 => array(0x3B7) - ,0x398 => array(0x3B8) - ,0x399 => array(0x3B9) - ,0x39A => array(0x3BA) - ,0x39B => array(0x3BB) - ,0x39C => array(0x3BC) - ,0x39D => array(0x3BD) - ,0x39E => array(0x3BE) - ,0x39F => array(0x3BF) - ,0x3A0 => array(0x3C0) - ,0x3A1 => array(0x3C1) - ,0x3A3 => array(0x3C3) - ,0x3A4 => array(0x3C4) - ,0x3A5 => array(0x3C5) - ,0x3A6 => array(0x3C6) - ,0x3A7 => array(0x3C7) - ,0x3A8 => array(0x3C8) - ,0x3A9 => array(0x3C9) - ,0x3AA => array(0x3CA) - ,0x3AB => array(0x3CB) - ,0x3B0 => array(0x3C5, 0x308, 0x301) - ,0x3C2 => array(0x3C3) - ,0x3D0 => array(0x3B2) - ,0x3D1 => array(0x3B8) - ,0x3D2 => array(0x3C5) - ,0x3D3 => array(0x3CD) - ,0x3D4 => array(0x3CB) - ,0x3D5 => array(0x3C6) - ,0x3D6 => array(0x3C0) - ,0x3D8 => array(0x3D9) - ,0x3DA => array(0x3DB) - ,0x3DC => array(0x3DD) - ,0x3DE => array(0x3DF) - ,0x3E0 => array(0x3E1) - ,0x3E2 => array(0x3E3) - ,0x3E4 => array(0x3E5) - ,0x3E6 => array(0x3E7) - ,0x3E8 => array(0x3E9) - ,0x3EA => array(0x3EB) - ,0x3EC => array(0x3ED) - ,0x3EE => array(0x3EF) - ,0x3F0 => array(0x3BA) - ,0x3F1 => array(0x3C1) - ,0x3F2 => array(0x3C3) - ,0x3F4 => array(0x3B8) - ,0x3F5 => array(0x3B5) - ,0x400 => array(0x450) - ,0x401 => array(0x451) - ,0x402 => array(0x452) - ,0x403 => array(0x453) - ,0x404 => array(0x454) - ,0x405 => array(0x455) - ,0x406 => array(0x456) - ,0x407 => array(0x457) - ,0x408 => array(0x458) - ,0x409 => array(0x459) - ,0x40A => array(0x45A) - ,0x40B => array(0x45B) - ,0x40C => array(0x45C) - ,0x40D => array(0x45D) - ,0x40E => array(0x45E) - ,0x40F => array(0x45F) - ,0x410 => array(0x430) - ,0x411 => array(0x431) - ,0x412 => array(0x432) - ,0x413 => array(0x433) - ,0x414 => array(0x434) - ,0x415 => array(0x435) - ,0x416 => array(0x436) - ,0x417 => array(0x437) - ,0x418 => array(0x438) - ,0x419 => array(0x439) - ,0x41A => array(0x43A) - ,0x41B => array(0x43B) - ,0x41C => array(0x43C) - ,0x41D => array(0x43D) - ,0x41E => array(0x43E) - ,0x41F => array(0x43F) - ,0x420 => array(0x440) - ,0x421 => array(0x441) - ,0x422 => array(0x442) - ,0x423 => array(0x443) - ,0x424 => array(0x444) - ,0x425 => array(0x445) - ,0x426 => array(0x446) - ,0x427 => array(0x447) - ,0x428 => array(0x448) - ,0x429 => array(0x449) - ,0x42A => array(0x44A) - ,0x42B => array(0x44B) - ,0x42C => array(0x44C) - ,0x42D => array(0x44D) - ,0x42E => array(0x44E) - ,0x42F => array(0x44F) - ,0x460 => array(0x461) - ,0x462 => array(0x463) - ,0x464 => array(0x465) - ,0x466 => array(0x467) - ,0x468 => array(0x469) - ,0x46A => array(0x46B) - ,0x46C => array(0x46D) - ,0x46E => array(0x46F) - ,0x470 => array(0x471) - ,0x472 => array(0x473) - ,0x474 => array(0x475) - ,0x476 => array(0x477) - ,0x478 => array(0x479) - ,0x47A => array(0x47B) - ,0x47C => array(0x47D) - ,0x47E => array(0x47F) - ,0x480 => array(0x481) - ,0x48A => array(0x48B) - ,0x48C => array(0x48D) - ,0x48E => array(0x48F) - ,0x490 => array(0x491) - ,0x492 => array(0x493) - ,0x494 => array(0x495) - ,0x496 => array(0x497) - ,0x498 => array(0x499) - ,0x49A => array(0x49B) - ,0x49C => array(0x49D) - ,0x49E => array(0x49F) - ,0x4A0 => array(0x4A1) - ,0x4A2 => array(0x4A3) - ,0x4A4 => array(0x4A5) - ,0x4A6 => array(0x4A7) - ,0x4A8 => array(0x4A9) - ,0x4AA => array(0x4AB) - ,0x4AC => array(0x4AD) - ,0x4AE => array(0x4AF) - ,0x4B0 => array(0x4B1) - ,0x4B2 => array(0x4B3) - ,0x4B4 => array(0x4B5) - ,0x4B6 => array(0x4B7) - ,0x4B8 => array(0x4B9) - ,0x4BA => array(0x4BB) - ,0x4BC => array(0x4BD) - ,0x4BE => array(0x4BF) - ,0x4C1 => array(0x4C2) - ,0x4C3 => array(0x4C4) - ,0x4C5 => array(0x4C6) - ,0x4C7 => array(0x4C8) - ,0x4C9 => array(0x4CA) - ,0x4CB => array(0x4CC) - ,0x4CD => array(0x4CE) - ,0x4D0 => array(0x4D1) - ,0x4D2 => array(0x4D3) - ,0x4D4 => array(0x4D5) - ,0x4D6 => array(0x4D7) - ,0x4D8 => array(0x4D9) - ,0x4DA => array(0x4DB) - ,0x4DC => array(0x4DD) - ,0x4DE => array(0x4DF) - ,0x4E0 => array(0x4E1) - ,0x4E2 => array(0x4E3) - ,0x4E4 => array(0x4E5) - ,0x4E6 => array(0x4E7) - ,0x4E8 => array(0x4E9) - ,0x4EA => array(0x4EB) - ,0x4EC => array(0x4ED) - ,0x4EE => array(0x4EF) - ,0x4F0 => array(0x4F1) - ,0x4F2 => array(0x4F3) - ,0x4F4 => array(0x4F5) - ,0x4F8 => array(0x4F9) - ,0x500 => array(0x501) - ,0x502 => array(0x503) - ,0x504 => array(0x505) - ,0x506 => array(0x507) - ,0x508 => array(0x509) - ,0x50A => array(0x50B) - ,0x50C => array(0x50D) - ,0x50E => array(0x50F) - ,0x531 => array(0x561) - ,0x532 => array(0x562) - ,0x533 => array(0x563) - ,0x534 => array(0x564) - ,0x535 => array(0x565) - ,0x536 => array(0x566) - ,0x537 => array(0x567) - ,0x538 => array(0x568) - ,0x539 => array(0x569) - ,0x53A => array(0x56A) - ,0x53B => array(0x56B) - ,0x53C => array(0x56C) - ,0x53D => array(0x56D) - ,0x53E => array(0x56E) - ,0x53F => array(0x56F) - ,0x540 => array(0x570) - ,0x541 => array(0x571) - ,0x542 => array(0x572) - ,0x543 => array(0x573) - ,0x544 => array(0x574) - ,0x545 => array(0x575) - ,0x546 => array(0x576) - ,0x547 => array(0x577) - ,0x548 => array(0x578) - ,0x549 => array(0x579) - ,0x54A => array(0x57A) - ,0x54B => array(0x57B) - ,0x54C => array(0x57C) - ,0x54D => array(0x57D) - ,0x54E => array(0x57E) - ,0x54F => array(0x57F) - ,0x550 => array(0x580) - ,0x551 => array(0x581) - ,0x552 => array(0x582) - ,0x553 => array(0x583) - ,0x554 => array(0x584) - ,0x555 => array(0x585) - ,0x556 => array(0x586) - ,0x587 => array(0x565, 0x582) - ,0xE33 => array(0xE4D, 0xE32) - ,0x1E00 => array(0x1E01) - ,0x1E02 => array(0x1E03) - ,0x1E04 => array(0x1E05) - ,0x1E06 => array(0x1E07) - ,0x1E08 => array(0x1E09) - ,0x1E0A => array(0x1E0B) - ,0x1E0C => array(0x1E0D) - ,0x1E0E => array(0x1E0F) - ,0x1E10 => array(0x1E11) - ,0x1E12 => array(0x1E13) - ,0x1E14 => array(0x1E15) - ,0x1E16 => array(0x1E17) - ,0x1E18 => array(0x1E19) - ,0x1E1A => array(0x1E1B) - ,0x1E1C => array(0x1E1D) - ,0x1E1E => array(0x1E1F) - ,0x1E20 => array(0x1E21) - ,0x1E22 => array(0x1E23) - ,0x1E24 => array(0x1E25) - ,0x1E26 => array(0x1E27) - ,0x1E28 => array(0x1E29) - ,0x1E2A => array(0x1E2B) - ,0x1E2C => array(0x1E2D) - ,0x1E2E => array(0x1E2F) - ,0x1E30 => array(0x1E31) - ,0x1E32 => array(0x1E33) - ,0x1E34 => array(0x1E35) - ,0x1E36 => array(0x1E37) - ,0x1E38 => array(0x1E39) - ,0x1E3A => array(0x1E3B) - ,0x1E3C => array(0x1E3D) - ,0x1E3E => array(0x1E3F) - ,0x1E40 => array(0x1E41) - ,0x1E42 => array(0x1E43) - ,0x1E44 => array(0x1E45) - ,0x1E46 => array(0x1E47) - ,0x1E48 => array(0x1E49) - ,0x1E4A => array(0x1E4B) - ,0x1E4C => array(0x1E4D) - ,0x1E4E => array(0x1E4F) - ,0x1E50 => array(0x1E51) - ,0x1E52 => array(0x1E53) - ,0x1E54 => array(0x1E55) - ,0x1E56 => array(0x1E57) - ,0x1E58 => array(0x1E59) - ,0x1E5A => array(0x1E5B) - ,0x1E5C => array(0x1E5D) - ,0x1E5E => array(0x1E5F) - ,0x1E60 => array(0x1E61) - ,0x1E62 => array(0x1E63) - ,0x1E64 => array(0x1E65) - ,0x1E66 => array(0x1E67) - ,0x1E68 => array(0x1E69) - ,0x1E6A => array(0x1E6B) - ,0x1E6C => array(0x1E6D) - ,0x1E6E => array(0x1E6F) - ,0x1E70 => array(0x1E71) - ,0x1E72 => array(0x1E73) - ,0x1E74 => array(0x1E75) - ,0x1E76 => array(0x1E77) - ,0x1E78 => array(0x1E79) - ,0x1E7A => array(0x1E7B) - ,0x1E7C => array(0x1E7D) - ,0x1E7E => array(0x1E7F) - ,0x1E80 => array(0x1E81) - ,0x1E82 => array(0x1E83) - ,0x1E84 => array(0x1E85) - ,0x1E86 => array(0x1E87) - ,0x1E88 => array(0x1E89) - ,0x1E8A => array(0x1E8B) - ,0x1E8C => array(0x1E8D) - ,0x1E8E => array(0x1E8F) - ,0x1E90 => array(0x1E91) - ,0x1E92 => array(0x1E93) - ,0x1E94 => array(0x1E95) - ,0x1E96 => array(0x68, 0x331) - ,0x1E97 => array(0x74, 0x308) - ,0x1E98 => array(0x77, 0x30A) - ,0x1E99 => array(0x79, 0x30A) - ,0x1E9A => array(0x61, 0x2BE) - ,0x1E9B => array(0x1E61) - ,0x1EA0 => array(0x1EA1) - ,0x1EA2 => array(0x1EA3) - ,0x1EA4 => array(0x1EA5) - ,0x1EA6 => array(0x1EA7) - ,0x1EA8 => array(0x1EA9) - ,0x1EAA => array(0x1EAB) - ,0x1EAC => array(0x1EAD) - ,0x1EAE => array(0x1EAF) - ,0x1EB0 => array(0x1EB1) - ,0x1EB2 => array(0x1EB3) - ,0x1EB4 => array(0x1EB5) - ,0x1EB6 => array(0x1EB7) - ,0x1EB8 => array(0x1EB9) - ,0x1EBA => array(0x1EBB) - ,0x1EBC => array(0x1EBD) - ,0x1EBE => array(0x1EBF) - ,0x1EC0 => array(0x1EC1) - ,0x1EC2 => array(0x1EC3) - ,0x1EC4 => array(0x1EC5) - ,0x1EC6 => array(0x1EC7) - ,0x1EC8 => array(0x1EC9) - ,0x1ECA => array(0x1ECB) - ,0x1ECC => array(0x1ECD) - ,0x1ECE => array(0x1ECF) - ,0x1ED0 => array(0x1ED1) - ,0x1ED2 => array(0x1ED3) - ,0x1ED4 => array(0x1ED5) - ,0x1ED6 => array(0x1ED7) - ,0x1ED8 => array(0x1ED9) - ,0x1EDA => array(0x1EDB) - ,0x1EDC => array(0x1EDD) - ,0x1EDE => array(0x1EDF) - ,0x1EE0 => array(0x1EE1) - ,0x1EE2 => array(0x1EE3) - ,0x1EE4 => array(0x1EE5) - ,0x1EE6 => array(0x1EE7) - ,0x1EE8 => array(0x1EE9) - ,0x1EEA => array(0x1EEB) - ,0x1EEC => array(0x1EED) - ,0x1EEE => array(0x1EEF) - ,0x1EF0 => array(0x1EF1) - ,0x1EF2 => array(0x1EF3) - ,0x1EF4 => array(0x1EF5) - ,0x1EF6 => array(0x1EF7) - ,0x1EF8 => array(0x1EF9) - ,0x1F08 => array(0x1F00) - ,0x1F09 => array(0x1F01) - ,0x1F0A => array(0x1F02) - ,0x1F0B => array(0x1F03) - ,0x1F0C => array(0x1F04) - ,0x1F0D => array(0x1F05) - ,0x1F0E => array(0x1F06) - ,0x1F0F => array(0x1F07) - ,0x1F18 => array(0x1F10) - ,0x1F19 => array(0x1F11) - ,0x1F1A => array(0x1F12) - ,0x1F1B => array(0x1F13) - ,0x1F1C => array(0x1F14) - ,0x1F1D => array(0x1F15) - ,0x1F28 => array(0x1F20) - ,0x1F29 => array(0x1F21) - ,0x1F2A => array(0x1F22) - ,0x1F2B => array(0x1F23) - ,0x1F2C => array(0x1F24) - ,0x1F2D => array(0x1F25) - ,0x1F2E => array(0x1F26) - ,0x1F2F => array(0x1F27) - ,0x1F38 => array(0x1F30) - ,0x1F39 => array(0x1F31) - ,0x1F3A => array(0x1F32) - ,0x1F3B => array(0x1F33) - ,0x1F3C => array(0x1F34) - ,0x1F3D => array(0x1F35) - ,0x1F3E => array(0x1F36) - ,0x1F3F => array(0x1F37) - ,0x1F48 => array(0x1F40) - ,0x1F49 => array(0x1F41) - ,0x1F4A => array(0x1F42) - ,0x1F4B => array(0x1F43) - ,0x1F4C => array(0x1F44) - ,0x1F4D => array(0x1F45) - ,0x1F50 => array(0x3C5, 0x313) - ,0x1F52 => array(0x3C5, 0x313, 0x300) - ,0x1F54 => array(0x3C5, 0x313, 0x301) - ,0x1F56 => array(0x3C5, 0x313, 0x342) - ,0x1F59 => array(0x1F51) - ,0x1F5B => array(0x1F53) - ,0x1F5D => array(0x1F55) - ,0x1F5F => array(0x1F57) - ,0x1F68 => array(0x1F60) - ,0x1F69 => array(0x1F61) - ,0x1F6A => array(0x1F62) - ,0x1F6B => array(0x1F63) - ,0x1F6C => array(0x1F64) - ,0x1F6D => array(0x1F65) - ,0x1F6E => array(0x1F66) - ,0x1F6F => array(0x1F67) - ,0x1F80 => array(0x1F00, 0x3B9) - ,0x1F81 => array(0x1F01, 0x3B9) - ,0x1F82 => array(0x1F02, 0x3B9) - ,0x1F83 => array(0x1F03, 0x3B9) - ,0x1F84 => array(0x1F04, 0x3B9) - ,0x1F85 => array(0x1F05, 0x3B9) - ,0x1F86 => array(0x1F06, 0x3B9) - ,0x1F87 => array(0x1F07, 0x3B9) - ,0x1F88 => array(0x1F00, 0x3B9) - ,0x1F89 => array(0x1F01, 0x3B9) - ,0x1F8A => array(0x1F02, 0x3B9) - ,0x1F8B => array(0x1F03, 0x3B9) - ,0x1F8C => array(0x1F04, 0x3B9) - ,0x1F8D => array(0x1F05, 0x3B9) - ,0x1F8E => array(0x1F06, 0x3B9) - ,0x1F8F => array(0x1F07, 0x3B9) - ,0x1F90 => array(0x1F20, 0x3B9) - ,0x1F91 => array(0x1F21, 0x3B9) - ,0x1F92 => array(0x1F22, 0x3B9) - ,0x1F93 => array(0x1F23, 0x3B9) - ,0x1F94 => array(0x1F24, 0x3B9) - ,0x1F95 => array(0x1F25, 0x3B9) - ,0x1F96 => array(0x1F26, 0x3B9) - ,0x1F97 => array(0x1F27, 0x3B9) - ,0x1F98 => array(0x1F20, 0x3B9) - ,0x1F99 => array(0x1F21, 0x3B9) - ,0x1F9A => array(0x1F22, 0x3B9) - ,0x1F9B => array(0x1F23, 0x3B9) - ,0x1F9C => array(0x1F24, 0x3B9) - ,0x1F9D => array(0x1F25, 0x3B9) - ,0x1F9E => array(0x1F26, 0x3B9) - ,0x1F9F => array(0x1F27, 0x3B9) - ,0x1FA0 => array(0x1F60, 0x3B9) - ,0x1FA1 => array(0x1F61, 0x3B9) - ,0x1FA2 => array(0x1F62, 0x3B9) - ,0x1FA3 => array(0x1F63, 0x3B9) - ,0x1FA4 => array(0x1F64, 0x3B9) - ,0x1FA5 => array(0x1F65, 0x3B9) - ,0x1FA6 => array(0x1F66, 0x3B9) - ,0x1FA7 => array(0x1F67, 0x3B9) - ,0x1FA8 => array(0x1F60, 0x3B9) - ,0x1FA9 => array(0x1F61, 0x3B9) - ,0x1FAA => array(0x1F62, 0x3B9) - ,0x1FAB => array(0x1F63, 0x3B9) - ,0x1FAC => array(0x1F64, 0x3B9) - ,0x1FAD => array(0x1F65, 0x3B9) - ,0x1FAE => array(0x1F66, 0x3B9) - ,0x1FAF => array(0x1F67, 0x3B9) - ,0x1FB2 => array(0x1F70, 0x3B9) - ,0x1FB3 => array(0x3B1, 0x3B9) - ,0x1FB4 => array(0x3AC, 0x3B9) - ,0x1FB6 => array(0x3B1, 0x342) - ,0x1FB7 => array(0x3B1, 0x342, 0x3B9) - ,0x1FB8 => array(0x1FB0) - ,0x1FB9 => array(0x1FB1) - ,0x1FBA => array(0x1F70) - ,0x1FBB => array(0x1F71) - ,0x1FBC => array(0x3B1, 0x3B9) - ,0x1FBE => array(0x3B9) - ,0x1FC2 => array(0x1F74, 0x3B9) - ,0x1FC3 => array(0x3B7, 0x3B9) - ,0x1FC4 => array(0x3AE, 0x3B9) - ,0x1FC6 => array(0x3B7, 0x342) - ,0x1FC7 => array(0x3B7, 0x342, 0x3B9) - ,0x1FC8 => array(0x1F72) - ,0x1FC9 => array(0x1F73) - ,0x1FCA => array(0x1F74) - ,0x1FCB => array(0x1F75) - ,0x1FCC => array(0x3B7, 0x3B9) - ,0x1FD2 => array(0x3B9, 0x308, 0x300) - ,0x1FD3 => array(0x3B9, 0x308, 0x301) - ,0x1FD6 => array(0x3B9, 0x342) - ,0x1FD7 => array(0x3B9, 0x308, 0x342) - ,0x1FD8 => array(0x1FD0) - ,0x1FD9 => array(0x1FD1) - ,0x1FDA => array(0x1F76) - ,0x1FDB => array(0x1F77) - ,0x1FE2 => array(0x3C5, 0x308, 0x300) - ,0x1FE3 => array(0x3C5, 0x308, 0x301) - ,0x1FE4 => array(0x3C1, 0x313) - ,0x1FE6 => array(0x3C5, 0x342) - ,0x1FE7 => array(0x3C5, 0x308, 0x342) - ,0x1FE8 => array(0x1FE0) - ,0x1FE9 => array(0x1FE1) - ,0x1FEA => array(0x1F7A) - ,0x1FEB => array(0x1F7B) - ,0x1FEC => array(0x1FE5) - ,0x1FF2 => array(0x1F7C, 0x3B9) - ,0x1FF3 => array(0x3C9, 0x3B9) - ,0x1FF4 => array(0x3CE, 0x3B9) - ,0x1FF6 => array(0x3C9, 0x342) - ,0x1FF7 => array(0x3C9, 0x342, 0x3B9) - ,0x1FF8 => array(0x1F78) - ,0x1FF9 => array(0x1F79) - ,0x1FFA => array(0x1F7C) - ,0x1FFB => array(0x1F7D) - ,0x1FFC => array(0x3C9, 0x3B9) - ,0x20A8 => array(0x72, 0x73) - ,0x2102 => array(0x63) - ,0x2103 => array(0xB0, 0x63) - ,0x2107 => array(0x25B) - ,0x2109 => array(0xB0, 0x66) - ,0x210B => array(0x68) - ,0x210C => array(0x68) - ,0x210D => array(0x68) - ,0x2110 => array(0x69) - ,0x2111 => array(0x69) - ,0x2112 => array(0x6C) - ,0x2115 => array(0x6E) - ,0x2116 => array(0x6E, 0x6F) - ,0x2119 => array(0x70) - ,0x211A => array(0x71) - ,0x211B => array(0x72) - ,0x211C => array(0x72) - ,0x211D => array(0x72) - ,0x2120 => array(0x73, 0x6D) - ,0x2121 => array(0x74, 0x65, 0x6C) - ,0x2122 => array(0x74, 0x6D) - ,0x2124 => array(0x7A) - ,0x2126 => array(0x3C9) - ,0x2128 => array(0x7A) - ,0x212A => array(0x6B) - ,0x212B => array(0xE5) - ,0x212C => array(0x62) - ,0x212D => array(0x63) - ,0x2130 => array(0x65) - ,0x2131 => array(0x66) - ,0x2133 => array(0x6D) - ,0x213E => array(0x3B3) - ,0x213F => array(0x3C0) - ,0x2145 => array(0x64) - ,0x2160 => array(0x2170) - ,0x2161 => array(0x2171) - ,0x2162 => array(0x2172) - ,0x2163 => array(0x2173) - ,0x2164 => array(0x2174) - ,0x2165 => array(0x2175) - ,0x2166 => array(0x2176) - ,0x2167 => array(0x2177) - ,0x2168 => array(0x2178) - ,0x2169 => array(0x2179) - ,0x216A => array(0x217A) - ,0x216B => array(0x217B) - ,0x216C => array(0x217C) - ,0x216D => array(0x217D) - ,0x216E => array(0x217E) - ,0x216F => array(0x217F) - ,0x24B6 => array(0x24D0) - ,0x24B7 => array(0x24D1) - ,0x24B8 => array(0x24D2) - ,0x24B9 => array(0x24D3) - ,0x24BA => array(0x24D4) - ,0x24BB => array(0x24D5) - ,0x24BC => array(0x24D6) - ,0x24BD => array(0x24D7) - ,0x24BE => array(0x24D8) - ,0x24BF => array(0x24D9) - ,0x24C0 => array(0x24DA) - ,0x24C1 => array(0x24DB) - ,0x24C2 => array(0x24DC) - ,0x24C3 => array(0x24DD) - ,0x24C4 => array(0x24DE) - ,0x24C5 => array(0x24DF) - ,0x24C6 => array(0x24E0) - ,0x24C7 => array(0x24E1) - ,0x24C8 => array(0x24E2) - ,0x24C9 => array(0x24E3) - ,0x24CA => array(0x24E4) - ,0x24CB => array(0x24E5) - ,0x24CC => array(0x24E6) - ,0x24CD => array(0x24E7) - ,0x24CE => array(0x24E8) - ,0x24CF => array(0x24E9) - ,0x3371 => array(0x68, 0x70, 0x61) - ,0x3373 => array(0x61, 0x75) - ,0x3375 => array(0x6F, 0x76) - ,0x3380 => array(0x70, 0x61) - ,0x3381 => array(0x6E, 0x61) - ,0x3382 => array(0x3BC, 0x61) - ,0x3383 => array(0x6D, 0x61) - ,0x3384 => array(0x6B, 0x61) - ,0x3385 => array(0x6B, 0x62) - ,0x3386 => array(0x6D, 0x62) - ,0x3387 => array(0x67, 0x62) - ,0x338A => array(0x70, 0x66) - ,0x338B => array(0x6E, 0x66) - ,0x338C => array(0x3BC, 0x66) - ,0x3390 => array(0x68, 0x7A) - ,0x3391 => array(0x6B, 0x68, 0x7A) - ,0x3392 => array(0x6D, 0x68, 0x7A) - ,0x3393 => array(0x67, 0x68, 0x7A) - ,0x3394 => array(0x74, 0x68, 0x7A) - ,0x33A9 => array(0x70, 0x61) - ,0x33AA => array(0x6B, 0x70, 0x61) - ,0x33AB => array(0x6D, 0x70, 0x61) - ,0x33AC => array(0x67, 0x70, 0x61) - ,0x33B4 => array(0x70, 0x76) - ,0x33B5 => array(0x6E, 0x76) - ,0x33B6 => array(0x3BC, 0x76) - ,0x33B7 => array(0x6D, 0x76) - ,0x33B8 => array(0x6B, 0x76) - ,0x33B9 => array(0x6D, 0x76) - ,0x33BA => array(0x70, 0x77) - ,0x33BB => array(0x6E, 0x77) - ,0x33BC => array(0x3BC, 0x77) - ,0x33BD => array(0x6D, 0x77) - ,0x33BE => array(0x6B, 0x77) - ,0x33BF => array(0x6D, 0x77) - ,0x33C0 => array(0x6B, 0x3C9) - ,0x33C1 => array(0x6D, 0x3C9) /* - ,0x33C2 => array(0x61, 0x2E, 0x6D, 0x2E) */ - ,0x33C3 => array(0x62, 0x71) - ,0x33C6 => array(0x63, 0x2215, 0x6B, 0x67) - ,0x33C7 => array(0x63, 0x6F, 0x2E) - ,0x33C8 => array(0x64, 0x62) - ,0x33C9 => array(0x67, 0x79) - ,0x33CB => array(0x68, 0x70) - ,0x33CD => array(0x6B, 0x6B) - ,0x33CE => array(0x6B, 0x6D) - ,0x33D7 => array(0x70, 0x68) - ,0x33D9 => array(0x70, 0x70, 0x6D) - ,0x33DA => array(0x70, 0x72) - ,0x33DC => array(0x73, 0x76) - ,0x33DD => array(0x77, 0x62) - ,0xFB00 => array(0x66, 0x66) - ,0xFB01 => array(0x66, 0x69) - ,0xFB02 => array(0x66, 0x6C) - ,0xFB03 => array(0x66, 0x66, 0x69) - ,0xFB04 => array(0x66, 0x66, 0x6C) - ,0xFB05 => array(0x73, 0x74) - ,0xFB06 => array(0x73, 0x74) - ,0xFB13 => array(0x574, 0x576) - ,0xFB14 => array(0x574, 0x565) - ,0xFB15 => array(0x574, 0x56B) - ,0xFB16 => array(0x57E, 0x576) - ,0xFB17 => array(0x574, 0x56D) - ,0xFF21 => array(0xFF41) - ,0xFF22 => array(0xFF42) - ,0xFF23 => array(0xFF43) - ,0xFF24 => array(0xFF44) - ,0xFF25 => array(0xFF45) - ,0xFF26 => array(0xFF46) - ,0xFF27 => array(0xFF47) - ,0xFF28 => array(0xFF48) - ,0xFF29 => array(0xFF49) - ,0xFF2A => array(0xFF4A) - ,0xFF2B => array(0xFF4B) - ,0xFF2C => array(0xFF4C) - ,0xFF2D => array(0xFF4D) - ,0xFF2E => array(0xFF4E) - ,0xFF2F => array(0xFF4F) - ,0xFF30 => array(0xFF50) - ,0xFF31 => array(0xFF51) - ,0xFF32 => array(0xFF52) - ,0xFF33 => array(0xFF53) - ,0xFF34 => array(0xFF54) - ,0xFF35 => array(0xFF55) - ,0xFF36 => array(0xFF56) - ,0xFF37 => array(0xFF57) - ,0xFF38 => array(0xFF58) - ,0xFF39 => array(0xFF59) - ,0xFF3A => array(0xFF5A) - ,0x10400 => array(0x10428) - ,0x10401 => array(0x10429) - ,0x10402 => array(0x1042A) - ,0x10403 => array(0x1042B) - ,0x10404 => array(0x1042C) - ,0x10405 => array(0x1042D) - ,0x10406 => array(0x1042E) - ,0x10407 => array(0x1042F) - ,0x10408 => array(0x10430) - ,0x10409 => array(0x10431) - ,0x1040A => array(0x10432) - ,0x1040B => array(0x10433) - ,0x1040C => array(0x10434) - ,0x1040D => array(0x10435) - ,0x1040E => array(0x10436) - ,0x1040F => array(0x10437) - ,0x10410 => array(0x10438) - ,0x10411 => array(0x10439) - ,0x10412 => array(0x1043A) - ,0x10413 => array(0x1043B) - ,0x10414 => array(0x1043C) - ,0x10415 => array(0x1043D) - ,0x10416 => array(0x1043E) - ,0x10417 => array(0x1043F) - ,0x10418 => array(0x10440) - ,0x10419 => array(0x10441) - ,0x1041A => array(0x10442) - ,0x1041B => array(0x10443) - ,0x1041C => array(0x10444) - ,0x1041D => array(0x10445) - ,0x1041E => array(0x10446) - ,0x1041F => array(0x10447) - ,0x10420 => array(0x10448) - ,0x10421 => array(0x10449) - ,0x10422 => array(0x1044A) - ,0x10423 => array(0x1044B) - ,0x10424 => array(0x1044C) - ,0x10425 => array(0x1044D) - ,0x1D400 => array(0x61) - ,0x1D401 => array(0x62) - ,0x1D402 => array(0x63) - ,0x1D403 => array(0x64) - ,0x1D404 => array(0x65) - ,0x1D405 => array(0x66) - ,0x1D406 => array(0x67) - ,0x1D407 => array(0x68) - ,0x1D408 => array(0x69) - ,0x1D409 => array(0x6A) - ,0x1D40A => array(0x6B) - ,0x1D40B => array(0x6C) - ,0x1D40C => array(0x6D) - ,0x1D40D => array(0x6E) - ,0x1D40E => array(0x6F) - ,0x1D40F => array(0x70) - ,0x1D410 => array(0x71) - ,0x1D411 => array(0x72) - ,0x1D412 => array(0x73) - ,0x1D413 => array(0x74) - ,0x1D414 => array(0x75) - ,0x1D415 => array(0x76) - ,0x1D416 => array(0x77) - ,0x1D417 => array(0x78) - ,0x1D418 => array(0x79) - ,0x1D419 => array(0x7A) - ,0x1D434 => array(0x61) - ,0x1D435 => array(0x62) - ,0x1D436 => array(0x63) - ,0x1D437 => array(0x64) - ,0x1D438 => array(0x65) - ,0x1D439 => array(0x66) - ,0x1D43A => array(0x67) - ,0x1D43B => array(0x68) - ,0x1D43C => array(0x69) - ,0x1D43D => array(0x6A) - ,0x1D43E => array(0x6B) - ,0x1D43F => array(0x6C) - ,0x1D440 => array(0x6D) - ,0x1D441 => array(0x6E) - ,0x1D442 => array(0x6F) - ,0x1D443 => array(0x70) - ,0x1D444 => array(0x71) - ,0x1D445 => array(0x72) - ,0x1D446 => array(0x73) - ,0x1D447 => array(0x74) - ,0x1D448 => array(0x75) - ,0x1D449 => array(0x76) - ,0x1D44A => array(0x77) - ,0x1D44B => array(0x78) - ,0x1D44C => array(0x79) - ,0x1D44D => array(0x7A) - ,0x1D468 => array(0x61) - ,0x1D469 => array(0x62) - ,0x1D46A => array(0x63) - ,0x1D46B => array(0x64) - ,0x1D46C => array(0x65) - ,0x1D46D => array(0x66) - ,0x1D46E => array(0x67) - ,0x1D46F => array(0x68) - ,0x1D470 => array(0x69) - ,0x1D471 => array(0x6A) - ,0x1D472 => array(0x6B) - ,0x1D473 => array(0x6C) - ,0x1D474 => array(0x6D) - ,0x1D475 => array(0x6E) - ,0x1D476 => array(0x6F) - ,0x1D477 => array(0x70) - ,0x1D478 => array(0x71) - ,0x1D479 => array(0x72) - ,0x1D47A => array(0x73) - ,0x1D47B => array(0x74) - ,0x1D47C => array(0x75) - ,0x1D47D => array(0x76) - ,0x1D47E => array(0x77) - ,0x1D47F => array(0x78) - ,0x1D480 => array(0x79) - ,0x1D481 => array(0x7A) - ,0x1D49C => array(0x61) - ,0x1D49E => array(0x63) - ,0x1D49F => array(0x64) - ,0x1D4A2 => array(0x67) - ,0x1D4A5 => array(0x6A) - ,0x1D4A6 => array(0x6B) - ,0x1D4A9 => array(0x6E) - ,0x1D4AA => array(0x6F) - ,0x1D4AB => array(0x70) - ,0x1D4AC => array(0x71) - ,0x1D4AE => array(0x73) - ,0x1D4AF => array(0x74) - ,0x1D4B0 => array(0x75) - ,0x1D4B1 => array(0x76) - ,0x1D4B2 => array(0x77) - ,0x1D4B3 => array(0x78) - ,0x1D4B4 => array(0x79) - ,0x1D4B5 => array(0x7A) - ,0x1D4D0 => array(0x61) - ,0x1D4D1 => array(0x62) - ,0x1D4D2 => array(0x63) - ,0x1D4D3 => array(0x64) - ,0x1D4D4 => array(0x65) - ,0x1D4D5 => array(0x66) - ,0x1D4D6 => array(0x67) - ,0x1D4D7 => array(0x68) - ,0x1D4D8 => array(0x69) - ,0x1D4D9 => array(0x6A) - ,0x1D4DA => array(0x6B) - ,0x1D4DB => array(0x6C) - ,0x1D4DC => array(0x6D) - ,0x1D4DD => array(0x6E) - ,0x1D4DE => array(0x6F) - ,0x1D4DF => array(0x70) - ,0x1D4E0 => array(0x71) - ,0x1D4E1 => array(0x72) - ,0x1D4E2 => array(0x73) - ,0x1D4E3 => array(0x74) - ,0x1D4E4 => array(0x75) - ,0x1D4E5 => array(0x76) - ,0x1D4E6 => array(0x77) - ,0x1D4E7 => array(0x78) - ,0x1D4E8 => array(0x79) - ,0x1D4E9 => array(0x7A) - ,0x1D504 => array(0x61) - ,0x1D505 => array(0x62) - ,0x1D507 => array(0x64) - ,0x1D508 => array(0x65) - ,0x1D509 => array(0x66) - ,0x1D50A => array(0x67) - ,0x1D50D => array(0x6A) - ,0x1D50E => array(0x6B) - ,0x1D50F => array(0x6C) - ,0x1D510 => array(0x6D) - ,0x1D511 => array(0x6E) - ,0x1D512 => array(0x6F) - ,0x1D513 => array(0x70) - ,0x1D514 => array(0x71) - ,0x1D516 => array(0x73) - ,0x1D517 => array(0x74) - ,0x1D518 => array(0x75) - ,0x1D519 => array(0x76) - ,0x1D51A => array(0x77) - ,0x1D51B => array(0x78) - ,0x1D51C => array(0x79) - ,0x1D538 => array(0x61) - ,0x1D539 => array(0x62) - ,0x1D53B => array(0x64) - ,0x1D53C => array(0x65) - ,0x1D53D => array(0x66) - ,0x1D53E => array(0x67) - ,0x1D540 => array(0x69) - ,0x1D541 => array(0x6A) - ,0x1D542 => array(0x6B) - ,0x1D543 => array(0x6C) - ,0x1D544 => array(0x6D) - ,0x1D546 => array(0x6F) - ,0x1D54A => array(0x73) - ,0x1D54B => array(0x74) - ,0x1D54C => array(0x75) - ,0x1D54D => array(0x76) - ,0x1D54E => array(0x77) - ,0x1D54F => array(0x78) - ,0x1D550 => array(0x79) - ,0x1D56C => array(0x61) - ,0x1D56D => array(0x62) - ,0x1D56E => array(0x63) - ,0x1D56F => array(0x64) - ,0x1D570 => array(0x65) - ,0x1D571 => array(0x66) - ,0x1D572 => array(0x67) - ,0x1D573 => array(0x68) - ,0x1D574 => array(0x69) - ,0x1D575 => array(0x6A) - ,0x1D576 => array(0x6B) - ,0x1D577 => array(0x6C) - ,0x1D578 => array(0x6D) - ,0x1D579 => array(0x6E) - ,0x1D57A => array(0x6F) - ,0x1D57B => array(0x70) - ,0x1D57C => array(0x71) - ,0x1D57D => array(0x72) - ,0x1D57E => array(0x73) - ,0x1D57F => array(0x74) - ,0x1D580 => array(0x75) - ,0x1D581 => array(0x76) - ,0x1D582 => array(0x77) - ,0x1D583 => array(0x78) - ,0x1D584 => array(0x79) - ,0x1D585 => array(0x7A) - ,0x1D5A0 => array(0x61) - ,0x1D5A1 => array(0x62) - ,0x1D5A2 => array(0x63) - ,0x1D5A3 => array(0x64) - ,0x1D5A4 => array(0x65) - ,0x1D5A5 => array(0x66) - ,0x1D5A6 => array(0x67) - ,0x1D5A7 => array(0x68) - ,0x1D5A8 => array(0x69) - ,0x1D5A9 => array(0x6A) - ,0x1D5AA => array(0x6B) - ,0x1D5AB => array(0x6C) - ,0x1D5AC => array(0x6D) - ,0x1D5AD => array(0x6E) - ,0x1D5AE => array(0x6F) - ,0x1D5AF => array(0x70) - ,0x1D5B0 => array(0x71) - ,0x1D5B1 => array(0x72) - ,0x1D5B2 => array(0x73) - ,0x1D5B3 => array(0x74) - ,0x1D5B4 => array(0x75) - ,0x1D5B5 => array(0x76) - ,0x1D5B6 => array(0x77) - ,0x1D5B7 => array(0x78) - ,0x1D5B8 => array(0x79) - ,0x1D5B9 => array(0x7A) - ,0x1D5D4 => array(0x61) - ,0x1D5D5 => array(0x62) - ,0x1D5D6 => array(0x63) - ,0x1D5D7 => array(0x64) - ,0x1D5D8 => array(0x65) - ,0x1D5D9 => array(0x66) - ,0x1D5DA => array(0x67) - ,0x1D5DB => array(0x68) - ,0x1D5DC => array(0x69) - ,0x1D5DD => array(0x6A) - ,0x1D5DE => array(0x6B) - ,0x1D5DF => array(0x6C) - ,0x1D5E0 => array(0x6D) - ,0x1D5E1 => array(0x6E) - ,0x1D5E2 => array(0x6F) - ,0x1D5E3 => array(0x70) - ,0x1D5E4 => array(0x71) - ,0x1D5E5 => array(0x72) - ,0x1D5E6 => array(0x73) - ,0x1D5E7 => array(0x74) - ,0x1D5E8 => array(0x75) - ,0x1D5E9 => array(0x76) - ,0x1D5EA => array(0x77) - ,0x1D5EB => array(0x78) - ,0x1D5EC => array(0x79) - ,0x1D5ED => array(0x7A) - ,0x1D608 => array(0x61) - ,0x1D609 => array(0x62) - ,0x1D60A => array(0x63) - ,0x1D60B => array(0x64) - ,0x1D60C => array(0x65) - ,0x1D60D => array(0x66) - ,0x1D60E => array(0x67) - ,0x1D60F => array(0x68) - ,0x1D610 => array(0x69) - ,0x1D611 => array(0x6A) - ,0x1D612 => array(0x6B) - ,0x1D613 => array(0x6C) - ,0x1D614 => array(0x6D) - ,0x1D615 => array(0x6E) - ,0x1D616 => array(0x6F) - ,0x1D617 => array(0x70) - ,0x1D618 => array(0x71) - ,0x1D619 => array(0x72) - ,0x1D61A => array(0x73) - ,0x1D61B => array(0x74) - ,0x1D61C => array(0x75) - ,0x1D61D => array(0x76) - ,0x1D61E => array(0x77) - ,0x1D61F => array(0x78) - ,0x1D620 => array(0x79) - ,0x1D621 => array(0x7A) - ,0x1D63C => array(0x61) - ,0x1D63D => array(0x62) - ,0x1D63E => array(0x63) - ,0x1D63F => array(0x64) - ,0x1D640 => array(0x65) - ,0x1D641 => array(0x66) - ,0x1D642 => array(0x67) - ,0x1D643 => array(0x68) - ,0x1D644 => array(0x69) - ,0x1D645 => array(0x6A) - ,0x1D646 => array(0x6B) - ,0x1D647 => array(0x6C) - ,0x1D648 => array(0x6D) - ,0x1D649 => array(0x6E) - ,0x1D64A => array(0x6F) - ,0x1D64B => array(0x70) - ,0x1D64C => array(0x71) - ,0x1D64D => array(0x72) - ,0x1D64E => array(0x73) - ,0x1D64F => array(0x74) - ,0x1D650 => array(0x75) - ,0x1D651 => array(0x76) - ,0x1D652 => array(0x77) - ,0x1D653 => array(0x78) - ,0x1D654 => array(0x79) - ,0x1D655 => array(0x7A) - ,0x1D670 => array(0x61) - ,0x1D671 => array(0x62) - ,0x1D672 => array(0x63) - ,0x1D673 => array(0x64) - ,0x1D674 => array(0x65) - ,0x1D675 => array(0x66) - ,0x1D676 => array(0x67) - ,0x1D677 => array(0x68) - ,0x1D678 => array(0x69) - ,0x1D679 => array(0x6A) - ,0x1D67A => array(0x6B) - ,0x1D67B => array(0x6C) - ,0x1D67C => array(0x6D) - ,0x1D67D => array(0x6E) - ,0x1D67E => array(0x6F) - ,0x1D67F => array(0x70) - ,0x1D680 => array(0x71) - ,0x1D681 => array(0x72) - ,0x1D682 => array(0x73) - ,0x1D683 => array(0x74) - ,0x1D684 => array(0x75) - ,0x1D685 => array(0x76) - ,0x1D686 => array(0x77) - ,0x1D687 => array(0x78) - ,0x1D688 => array(0x79) - ,0x1D689 => array(0x7A) - ,0x1D6A8 => array(0x3B1) - ,0x1D6A9 => array(0x3B2) - ,0x1D6AA => array(0x3B3) - ,0x1D6AB => array(0x3B4) - ,0x1D6AC => array(0x3B5) - ,0x1D6AD => array(0x3B6) - ,0x1D6AE => array(0x3B7) - ,0x1D6AF => array(0x3B8) - ,0x1D6B0 => array(0x3B9) - ,0x1D6B1 => array(0x3BA) - ,0x1D6B2 => array(0x3BB) - ,0x1D6B3 => array(0x3BC) - ,0x1D6B4 => array(0x3BD) - ,0x1D6B5 => array(0x3BE) - ,0x1D6B6 => array(0x3BF) - ,0x1D6B7 => array(0x3C0) - ,0x1D6B8 => array(0x3C1) - ,0x1D6B9 => array(0x3B8) - ,0x1D6BA => array(0x3C3) - ,0x1D6BB => array(0x3C4) - ,0x1D6BC => array(0x3C5) - ,0x1D6BD => array(0x3C6) - ,0x1D6BE => array(0x3C7) - ,0x1D6BF => array(0x3C8) - ,0x1D6C0 => array(0x3C9) - ,0x1D6D3 => array(0x3C3) - ,0x1D6E2 => array(0x3B1) - ,0x1D6E3 => array(0x3B2) - ,0x1D6E4 => array(0x3B3) - ,0x1D6E5 => array(0x3B4) - ,0x1D6E6 => array(0x3B5) - ,0x1D6E7 => array(0x3B6) - ,0x1D6E8 => array(0x3B7) - ,0x1D6E9 => array(0x3B8) - ,0x1D6EA => array(0x3B9) - ,0x1D6EB => array(0x3BA) - ,0x1D6EC => array(0x3BB) - ,0x1D6ED => array(0x3BC) - ,0x1D6EE => array(0x3BD) - ,0x1D6EF => array(0x3BE) - ,0x1D6F0 => array(0x3BF) - ,0x1D6F1 => array(0x3C0) - ,0x1D6F2 => array(0x3C1) - ,0x1D6F3 => array(0x3B8) - ,0x1D6F4 => array(0x3C3) - ,0x1D6F5 => array(0x3C4) - ,0x1D6F6 => array(0x3C5) - ,0x1D6F7 => array(0x3C6) - ,0x1D6F8 => array(0x3C7) - ,0x1D6F9 => array(0x3C8) - ,0x1D6FA => array(0x3C9) - ,0x1D70D => array(0x3C3) - ,0x1D71C => array(0x3B1) - ,0x1D71D => array(0x3B2) - ,0x1D71E => array(0x3B3) - ,0x1D71F => array(0x3B4) - ,0x1D720 => array(0x3B5) - ,0x1D721 => array(0x3B6) - ,0x1D722 => array(0x3B7) - ,0x1D723 => array(0x3B8) - ,0x1D724 => array(0x3B9) - ,0x1D725 => array(0x3BA) - ,0x1D726 => array(0x3BB) - ,0x1D727 => array(0x3BC) - ,0x1D728 => array(0x3BD) - ,0x1D729 => array(0x3BE) - ,0x1D72A => array(0x3BF) - ,0x1D72B => array(0x3C0) - ,0x1D72C => array(0x3C1) - ,0x1D72D => array(0x3B8) - ,0x1D72E => array(0x3C3) - ,0x1D72F => array(0x3C4) - ,0x1D730 => array(0x3C5) - ,0x1D731 => array(0x3C6) - ,0x1D732 => array(0x3C7) - ,0x1D733 => array(0x3C8) - ,0x1D734 => array(0x3C9) - ,0x1D747 => array(0x3C3) - ,0x1D756 => array(0x3B1) - ,0x1D757 => array(0x3B2) - ,0x1D758 => array(0x3B3) - ,0x1D759 => array(0x3B4) - ,0x1D75A => array(0x3B5) - ,0x1D75B => array(0x3B6) - ,0x1D75C => array(0x3B7) - ,0x1D75D => array(0x3B8) - ,0x1D75E => array(0x3B9) - ,0x1D75F => array(0x3BA) - ,0x1D760 => array(0x3BB) - ,0x1D761 => array(0x3BC) - ,0x1D762 => array(0x3BD) - ,0x1D763 => array(0x3BE) - ,0x1D764 => array(0x3BF) - ,0x1D765 => array(0x3C0) - ,0x1D766 => array(0x3C1) - ,0x1D767 => array(0x3B8) - ,0x1D768 => array(0x3C3) - ,0x1D769 => array(0x3C4) - ,0x1D76A => array(0x3C5) - ,0x1D76B => array(0x3C6) - ,0x1D76C => array(0x3C7) - ,0x1D76D => array(0x3C8) - ,0x1D76E => array(0x3C9) - ,0x1D781 => array(0x3C3) - ,0x1D790 => array(0x3B1) - ,0x1D791 => array(0x3B2) - ,0x1D792 => array(0x3B3) - ,0x1D793 => array(0x3B4) - ,0x1D794 => array(0x3B5) - ,0x1D795 => array(0x3B6) - ,0x1D796 => array(0x3B7) - ,0x1D797 => array(0x3B8) - ,0x1D798 => array(0x3B9) - ,0x1D799 => array(0x3BA) - ,0x1D79A => array(0x3BB) - ,0x1D79B => array(0x3BC) - ,0x1D79C => array(0x3BD) - ,0x1D79D => array(0x3BE) - ,0x1D79E => array(0x3BF) - ,0x1D79F => array(0x3C0) - ,0x1D7A0 => array(0x3C1) - ,0x1D7A1 => array(0x3B8) - ,0x1D7A2 => array(0x3C3) - ,0x1D7A3 => array(0x3C4) - ,0x1D7A4 => array(0x3C5) - ,0x1D7A5 => array(0x3C6) - ,0x1D7A6 => array(0x3C7) - ,0x1D7A7 => array(0x3C8) - ,0x1D7A8 => array(0x3C9) - ,0x1D7BB => array(0x3C3) - ,0x3F9 => array(0x3C3) - ,0x1D2C => array(0x61) - ,0x1D2D => array(0xE6) - ,0x1D2E => array(0x62) - ,0x1D30 => array(0x64) - ,0x1D31 => array(0x65) - ,0x1D32 => array(0x1DD) - ,0x1D33 => array(0x67) - ,0x1D34 => array(0x68) - ,0x1D35 => array(0x69) - ,0x1D36 => array(0x6A) - ,0x1D37 => array(0x6B) - ,0x1D38 => array(0x6C) - ,0x1D39 => array(0x6D) - ,0x1D3A => array(0x6E) - ,0x1D3C => array(0x6F) - ,0x1D3D => array(0x223) - ,0x1D3E => array(0x70) - ,0x1D3F => array(0x72) - ,0x1D40 => array(0x74) - ,0x1D41 => array(0x75) - ,0x1D42 => array(0x77) - ,0x213B => array(0x66, 0x61, 0x78) - ,0x3250 => array(0x70, 0x74, 0x65) - ,0x32CC => array(0x68, 0x67) - ,0x32CE => array(0x65, 0x76) - ,0x32CF => array(0x6C, 0x74, 0x64) - ,0x337A => array(0x69, 0x75) - ,0x33DE => array(0x76, 0x2215, 0x6D) - ,0x33DF => array(0x61, 0x2215, 0x6D) - ) - ,'norm_combcls' => array - (0x334 => 1 - ,0x335 => 1 - ,0x336 => 1 - ,0x337 => 1 - ,0x338 => 1 - ,0x93C => 7 - ,0x9BC => 7 - ,0xA3C => 7 - ,0xABC => 7 - ,0xB3C => 7 - ,0xCBC => 7 - ,0x1037 => 7 - ,0x3099 => 8 - ,0x309A => 8 - ,0x94D => 9 - ,0x9CD => 9 - ,0xA4D => 9 - ,0xACD => 9 - ,0xB4D => 9 - ,0xBCD => 9 - ,0xC4D => 9 - ,0xCCD => 9 - ,0xD4D => 9 - ,0xDCA => 9 - ,0xE3A => 9 - ,0xF84 => 9 - ,0x1039 => 9 - ,0x1714 => 9 - ,0x1734 => 9 - ,0x17D2 => 9 - ,0x5B0 => 10 - ,0x5B1 => 11 - ,0x5B2 => 12 - ,0x5B3 => 13 - ,0x5B4 => 14 - ,0x5B5 => 15 - ,0x5B6 => 16 - ,0x5B7 => 17 - ,0x5B8 => 18 - ,0x5B9 => 19 - ,0x5BB => 20 - ,0x5Bc => 21 - ,0x5BD => 22 - ,0x5BF => 23 - ,0x5C1 => 24 - ,0x5C2 => 25 - ,0xFB1E => 26 - ,0x64B => 27 - ,0x64C => 28 - ,0x64D => 29 - ,0x64E => 30 - ,0x64F => 31 - ,0x650 => 32 - ,0x651 => 33 - ,0x652 => 34 - ,0x670 => 35 - ,0x711 => 36 - ,0xC55 => 84 - ,0xC56 => 91 - ,0xE38 => 103 - ,0xE39 => 103 - ,0xE48 => 107 - ,0xE49 => 107 - ,0xE4A => 107 - ,0xE4B => 107 - ,0xEB8 => 118 - ,0xEB9 => 118 - ,0xEC8 => 122 - ,0xEC9 => 122 - ,0xECA => 122 - ,0xECB => 122 - ,0xF71 => 129 - ,0xF72 => 130 - ,0xF7A => 130 - ,0xF7B => 130 - ,0xF7C => 130 - ,0xF7D => 130 - ,0xF80 => 130 - ,0xF74 => 132 - ,0x321 => 202 - ,0x322 => 202 - ,0x327 => 202 - ,0x328 => 202 - ,0x31B => 216 - ,0xF39 => 216 - ,0x1D165 => 216 - ,0x1D166 => 216 - ,0x1D16E => 216 - ,0x1D16F => 216 - ,0x1D170 => 216 - ,0x1D171 => 216 - ,0x1D172 => 216 - ,0x302A => 218 - ,0x316 => 220 - ,0x317 => 220 - ,0x318 => 220 - ,0x319 => 220 - ,0x31C => 220 - ,0x31D => 220 - ,0x31E => 220 - ,0x31F => 220 - ,0x320 => 220 - ,0x323 => 220 - ,0x324 => 220 - ,0x325 => 220 - ,0x326 => 220 - ,0x329 => 220 - ,0x32A => 220 - ,0x32B => 220 - ,0x32C => 220 - ,0x32D => 220 - ,0x32E => 220 - ,0x32F => 220 - ,0x330 => 220 - ,0x331 => 220 - ,0x332 => 220 - ,0x333 => 220 - ,0x339 => 220 - ,0x33A => 220 - ,0x33B => 220 - ,0x33C => 220 - ,0x347 => 220 - ,0x348 => 220 - ,0x349 => 220 - ,0x34D => 220 - ,0x34E => 220 - ,0x353 => 220 - ,0x354 => 220 - ,0x355 => 220 - ,0x356 => 220 - ,0x591 => 220 - ,0x596 => 220 - ,0x59B => 220 - ,0x5A3 => 220 - ,0x5A4 => 220 - ,0x5A5 => 220 - ,0x5A6 => 220 - ,0x5A7 => 220 - ,0x5AA => 220 - ,0x655 => 220 - ,0x656 => 220 - ,0x6E3 => 220 - ,0x6EA => 220 - ,0x6ED => 220 - ,0x731 => 220 - ,0x734 => 220 - ,0x737 => 220 - ,0x738 => 220 - ,0x739 => 220 - ,0x73B => 220 - ,0x73C => 220 - ,0x73E => 220 - ,0x742 => 220 - ,0x744 => 220 - ,0x746 => 220 - ,0x748 => 220 - ,0x952 => 220 - ,0xF18 => 220 - ,0xF19 => 220 - ,0xF35 => 220 - ,0xF37 => 220 - ,0xFC6 => 220 - ,0x193B => 220 - ,0x20E8 => 220 - ,0x1D17B => 220 - ,0x1D17C => 220 - ,0x1D17D => 220 - ,0x1D17E => 220 - ,0x1D17F => 220 - ,0x1D180 => 220 - ,0x1D181 => 220 - ,0x1D182 => 220 - ,0x1D18A => 220 - ,0x1D18B => 220 - ,0x59A => 222 - ,0x5AD => 222 - ,0x1929 => 222 - ,0x302D => 222 - ,0x302E => 224 - ,0x302F => 224 - ,0x1D16D => 226 - ,0x5AE => 228 - ,0x18A9 => 228 - ,0x302B => 228 - ,0x300 => 230 - ,0x301 => 230 - ,0x302 => 230 - ,0x303 => 230 - ,0x304 => 230 - ,0x305 => 230 - ,0x306 => 230 - ,0x307 => 230 - ,0x308 => 230 - ,0x309 => 230 - ,0x30A => 230 - ,0x30B => 230 - ,0x30C => 230 - ,0x30D => 230 - ,0x30E => 230 - ,0x30F => 230 - ,0x310 => 230 - ,0x311 => 230 - ,0x312 => 230 - ,0x313 => 230 - ,0x314 => 230 - ,0x33D => 230 - ,0x33E => 230 - ,0x33F => 230 - ,0x340 => 230 - ,0x341 => 230 - ,0x342 => 230 - ,0x343 => 230 - ,0x344 => 230 - ,0x346 => 230 - ,0x34A => 230 - ,0x34B => 230 - ,0x34C => 230 - ,0x350 => 230 - ,0x351 => 230 - ,0x352 => 230 - ,0x357 => 230 - ,0x363 => 230 - ,0x364 => 230 - ,0x365 => 230 - ,0x366 => 230 - ,0x367 => 230 - ,0x368 => 230 - ,0x369 => 230 - ,0x36A => 230 - ,0x36B => 230 - ,0x36C => 230 - ,0x36D => 230 - ,0x36E => 230 - ,0x36F => 230 - ,0x483 => 230 - ,0x484 => 230 - ,0x485 => 230 - ,0x486 => 230 - ,0x592 => 230 - ,0x593 => 230 - ,0x594 => 230 - ,0x595 => 230 - ,0x597 => 230 - ,0x598 => 230 - ,0x599 => 230 - ,0x59C => 230 - ,0x59D => 230 - ,0x59E => 230 - ,0x59F => 230 - ,0x5A0 => 230 - ,0x5A1 => 230 - ,0x5A8 => 230 - ,0x5A9 => 230 - ,0x5AB => 230 - ,0x5AC => 230 - ,0x5AF => 230 - ,0x5C4 => 230 - ,0x610 => 230 - ,0x611 => 230 - ,0x612 => 230 - ,0x613 => 230 - ,0x614 => 230 - ,0x615 => 230 - ,0x653 => 230 - ,0x654 => 230 - ,0x657 => 230 - ,0x658 => 230 - ,0x6D6 => 230 - ,0x6D7 => 230 - ,0x6D8 => 230 - ,0x6D9 => 230 - ,0x6DA => 230 - ,0x6DB => 230 - ,0x6DC => 230 - ,0x6DF => 230 - ,0x6E0 => 230 - ,0x6E1 => 230 - ,0x6E2 => 230 - ,0x6E4 => 230 - ,0x6E7 => 230 - ,0x6E8 => 230 - ,0x6EB => 230 - ,0x6EC => 230 - ,0x730 => 230 - ,0x732 => 230 - ,0x733 => 230 - ,0x735 => 230 - ,0x736 => 230 - ,0x73A => 230 - ,0x73D => 230 - ,0x73F => 230 - ,0x740 => 230 - ,0x741 => 230 - ,0x743 => 230 - ,0x745 => 230 - ,0x747 => 230 - ,0x749 => 230 - ,0x74A => 230 - ,0x951 => 230 - ,0x953 => 230 - ,0x954 => 230 - ,0xF82 => 230 - ,0xF83 => 230 - ,0xF86 => 230 - ,0xF87 => 230 - ,0x170D => 230 - ,0x193A => 230 - ,0x20D0 => 230 - ,0x20D1 => 230 - ,0x20D4 => 230 - ,0x20D5 => 230 - ,0x20D6 => 230 - ,0x20D7 => 230 - ,0x20DB => 230 - ,0x20DC => 230 - ,0x20E1 => 230 - ,0x20E7 => 230 - ,0x20E9 => 230 - ,0xFE20 => 230 - ,0xFE21 => 230 - ,0xFE22 => 230 - ,0xFE23 => 230 - ,0x1D185 => 230 - ,0x1D186 => 230 - ,0x1D187 => 230 - ,0x1D189 => 230 - ,0x1D188 => 230 - ,0x1D1AA => 230 - ,0x1D1AB => 230 - ,0x1D1AC => 230 - ,0x1D1AD => 230 - ,0x315 => 232 - ,0x31A => 232 - ,0x302C => 232 - ,0x35F => 233 - ,0x362 => 233 - ,0x35D => 234 - ,0x35E => 234 - ,0x360 => 234 - ,0x361 => 234 - ,0x345 => 240 - ) - ); -} -?> \ No newline at end of file diff --git a/core/controller/admincontroller.php b/core/controller/admincontroller.php deleted file mode 100644 index d50f561..0000000 --- a/core/controller/admincontroller.php +++ /dev/null @@ -1,433 +0,0 @@ -table->setHeader - */ - public $tableSchema = null; - public $formSchema = array(); - - public $menu; - public $path; - public $table; - - public function __construct() - { - $this->path = new PathMenu(); - $this->menu = new PageMenu(); - $this->table = new ListTable(); - } - - /** - */ - function setUp() - { - $this->table->addMenuItem($this->aUrl('delete'), 'удалить', false, 'all', 'warning'); - //$this->table->addMenuItem($this->nUrl('form'), 'редактировать', 'edit-24.png'); - } - - function saveParameters($args, $list) - { - foreach ($list as $item) { - $args->session()->set(array($this, $item), $args->get($item)); - } - } - - protected function getJSONList(/*Mapper*/ $model, Collection $request) - { - $result = array(); - $this->saveParameters($request, array('size','page','desc', 'key')); - - $result['list'] = $model->findAll($request, $request->get('ref')); - $result['size'] = $model->getCount($request, $request->get('ref')); - return json::encode($result); - } - - /** - * Удаление сторк из таблицы - */ - public function actionDelete(HttpRequest $request) - { - $model = $this->getModel($this->useModel); - // Почему table_item ??? - $list = ($request->get('table_item')) ? $request->get('table_item'): $request->get('id'); - $model->deleteList($list); - - return $this->getJSONList($model, $request); - } - - /** - * Ответ на запрос по поиску - */ - public function actionSearch(HttpRequest $request) - { - $model = $this->getModel($this->useModel); - $model->addFilter($model->requestToSQL($request, $this->formSchema)); - - return $this->getJSONList($model, $request); - } - - /** - * Список элементов - */ - public function actionList(HttpRequest $request) - { - $model = $this->getModel($this->useModel); - return $this->getJSONList($model, $request); - } - - - private function setFormSchema() - { - require_once 'core/mapper/uimapper.php'; - - $model = $this->getModel($this->useModel); - $ui = new UIMapper($model); - - $this->formSchema = $ui->getFormSchema(); - } - - /** - * Сохранение формы - */ - function beforeSave(/*Model*/ $item, Collection $request) - { - if (empty($this->formSchema)) { - $this->setFormSchema(); - } - // Сделать отображение Формы в обьект и обратно <-- Убрать в beforeSave - foreach ($this->formSchema as $key => $conv) { - list($value, $type) = $conv; - $item->$value = call_user_func(array('Cast', 'to_' . $type), $request->get($key)); // Здесть нужно преобразовывать тип значения - } - } - - /** - * Обновление формы - */ - function formUpdate(TForm $form, Collection $request) - { - } - - /** - * Загрузка формы - */ - function beforeLoad(/*Model*/ $item, TForm $form) - { - if (empty($this->formSchema)) { - $this->setFormSchema(); - } - // Вставка значений из данных в форму - // Отображение обьекта в поля формы - $form->fill($item, $this->formSchema); - } - - // Проверка ввода - protected function validate($validator, $request) - { - } - - /** - * Действие для проверки формы - */ - public function actionValidate($request) - { - require_once "core/validator/validator.php"; - $validator = new Validator(); - $validator->addRuleList($this->schema); - - // Действия до проверки формы - $this->validate($validator, $request); // <--| - $validator->validate($request); // --| - // Проверка формы - if (!$validator->isValid()) { - return json::encode($validator->getErrorMsg()); - } - return json::encode(true); - } - - /** - * Инициализация формы - */ - protected function formSetup($form, $id = null, $ref = null) - { - if (empty($this->schema)) { - $model = $this->getModel($this->useModel); - $ui = new UIMapper($model); - $schema = $ui->getEditSchema(); - - $form->addFieldList($schema); - } else { - $form->addFieldList($this->schema); - } - } - - /** - * Добавление пользователя - */ - public function actionAdd(HttpRequest $request) - { - require_once "core/validator/validator.php"; - // {{{ тоже может быть один ref или несколько - $ref = $request->get('ref'); - $this->addParameter('ref', $ref); // Добавляет параметр в url - /// }}} - - if ($this->checkPageId($request, $request->get('page'))) { - // Проверка - $validator = new Validator(); - $validator->addRuleList($this->schema); - - // Действия до проверки формы - $this->validate($validator, $request); // <--| - $validator->validate($request); // --| - // Проверка формы - if (!$validator->isValid()) { - $request->setAction('form'); - $this->getActionPath($request); - - $form = new TForm(); - $this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы - - $form->setValues($request); // <-- Убрать в formUpdate - $this->formUpdate($form, $request); - - $form->setError($validator); // Установка ошибок для формы - - $tpl = $this->formPage($form, $request); - $id = $request->get('id'); - if ($id) { // Редактирование - $tpl->action = forceUrl($this->nUrl('add', array('id' => $id, 'page' => $this->getPageId($request)))); // action Совйство формы - } - return $tpl /*->execute()*/; - } - - // Нужен тест для формы - $model = $this->getModel($this->useModel); - $className = $model->className; - $item = new $className(); - - // Сохраняем значение в базе данных - $item->id = $request->get('id'); - // Если таблица связана с другой таблицей - if ($request->get('ref') && $model->reference[1]) { - $ref_id = $model->reference[1]; - $item->$ref_id = $request->get('ref'); - } - - // Подготовка к сохранению - $this->beforeSave($item, $request); // Сюдаже и истрия переходов - // nextId ??? или выход или новая форма для создания новости - $model->saveDB($item, $request); - } - - // Для страницы со списком id -> идентефикатор родительской таблицы !!?? -// $request->set('id', $request->get('ref')); - if ($request->get('apply')) { - $request->setAction('form'); - return $this->forward('actionForm', $request); - } - return $this->forward('actionIndex', $request); - } - - /** - * Заголовок - */ - private function setTitlePath($ref) - { - if ($ref) { - $model = $this->getModel($this->useModel); - if (is_array($model->reference) && $model->reference[0]) { - $refmodel = $this->getModel($model->reference[0]); - try { - $parent = $refmodel->findById($ref); - $this->path->addTitle($parent->getTitle()); // Заголовок к подписям путей - } catch (Exception $e) { - // Не найден заголовок потому что неправильно определен родительский элемент - } - } - } - } - - /** - * Форма для редактирования - */ - public function actionForm(HttpRequest $request) - { - $this->getActionPath($request); - $ref = $request->get('ref'); - $this->addParameter('ref', $ref); // Добавляет параметр в url - $this->setTitlePath($ref); - - $model = $this->getModel($this->useModel); - $form = new TForm(); // Показываем форму - $form->header = 'Редактирование записи'; - $this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы - - $list = $request->get('table_item'); - $id = ($list[0]) ? $list[0] : $request->get('id'); - - $tpl = $this->formPage ($form, $request); - if ($id) { // Редактирование - $form->action = forceUrl($this->nUrl('add', array('id' => $id, 'page' => $this->getPageId($request)))); // action Свойство формы - $item = $model->findById($id); - // Загрузка формы - $this->beforeLoad($item, $form); - /// - } - return $tpl; - } - - /** - */ - function tableSetup($table, $id = null, $ref = null) - { - // FIXME: После замены везде $tableSchema -> table->setHeader удалить! - if ($this->tableSchema) { - $table->setHeader($this->tableSchema); - } else { - // Настройка таблицы отображения по схеме данных - require_once 'core/mapper/uimapper.php'; - $model = $this->getModel($this->useModel); - $ui = new UIMapper($model); - $schema = $ui->getTableSchema(); - $schema[0]['action'] = $table->getFirstItem(); - - $table->setHeader($schema); - } - } - - /** - */ - public function actionIndex(HttpRequest $request) - { - $this->getActionPath($request, 'index'); - // Такое мета действие наверное можно вынести в отдельный класс - return $this->metaActionIndex($request, array($this, 'tableSetup'), $this->aUrl('list')); - } - - /** - * Страница по умолчанию - */ - public function metaActionIndex(HttpRequest $request, $setup, $list) - { - // может быть одно ref или несколько - // {{{ история переходов - $ref = null; - if ($request->get('ref')) { - $ref = $request->get('ref'); - } else if ($request->session()->get('ref')) { - $ref = $request->session()->get('ref'); - } - - $request->session->set('ref', $ref); - $this->addParameter('ref', $ref); - // }}} - $this->setTitlePath($ref); - - $tpl = $this->getView('list'); - - // Помошники действий - $this->callHelpers($request); - // Таблица - if ($request->session()->get(strtolower(get_class($this)))) { - $session = $request->session()->get(strtolower(get_class($this))); - if (isset($session['view'])) { - $this->table->setView($session['view']); - } - $this->table->setData('state', array( - 'page' => $session['page'], - 'size' => $session['size'], - 'desc' => $session['desc'])); - - $this->table->setData('sorter', $session['key']); - if (isset($session['desc'])) { - $this->table->setData('desc', $session['desc']); - } - } - - call_user_func($setup, $this->table, $request->get('id'), $ref);// --> Эквивалент formSetup - $this->table->setAction($list); - // - $tpl->menu_path = $this->path->getItems(); - - // Поиск - $search = new SearchDialog(); - $search->setTitle('Поиск'); - $search->setAction($this->aUrl('search')); - $search->setFriend($this->table); - $search->addFields($this->schemaSearch); - - // Настройки - $setup = new SetupDialog(); - $setup->setTitle('Настройки'); - $setup->setAction($this->nUrl('setup')); - $setup->setFriend($this->table); - - // Меню - $this->menu->addMenuItem('?menu=toggle&id=' . $search->getName(), 'поиск', 'actions/system-search'); // Стандартный размер для иконок 22-24px - $this->menu->addMenuItem('?menu=toggle&id=' . $setup->getName(), 'настройки', 'categories/applications-system'); - // Добавление компонентов - $this->addChild('menu', $this->menu); - $this->addChild('search', $search); - $this->addChild('setup', $setup); - $this->addChild('table', $this->table); - // - return $tpl; - } - - /** - */ - public function actionSetup($request) - { - $left = explode(",", $request->get('left')); - $right = explode(",", $request->get('right')); - - $$request->session()->set(strtolower(get_class($this)), - array('view' => array('left' => $left, 'right' => $right))); - - return $this->forward('actionIndex', $request); - } - - /** - */ - private function formPage($form, $request) - { - $view = $this->getView('form'); - $view->setView('form', $form); - $view->action = forceUrl($this->nUrl('add', array('page' => $this->getPageId($request)))); // Действие для формы - - $view->menu_path = $this->path->getItems(); - $view->back = $this->path->getPrev(); - return $view; - } - - // Тоже убрать в метод Controller_Model - function getActionPath(HttpRequest $request/*, $action = false*/) - { - require_once 'state.php'; - $this->_getActionPath()->getPath($this, ($action) ? $action : $request->getAction()); - } -} diff --git a/core/controller/component.php b/core/controller/component.php deleted file mode 100644 index 0d3ecd6..0000000 --- a/core/controller/component.php +++ /dev/null @@ -1,185 +0,0 @@ -getInstance - public $template; - - function __construct() - { - self::$_uid ++; - $this->uid = self::$_uid; - } - - function getUID() - { - return 'component:'. $this->uid; - } - - public function getView($name) - { - require_once "core/view/compositeview.php"; - // - $template = ($this->template) ? $this->template : $this->_registry->readKey(array('system', 'template')); - // Загружать шаблон по умолчанию если не найден текущий - if (is_dir(Path::join($this->viewPath, 'templates', $template))) { - $template_file = Path::join($this->viewPath, 'templates', $template, $name); - } else { - $template_file = Path::join($this->viewPath, 'templates', 'modern', $name); - } - $tpl = new View_Composite($template_file); - - $tpl->script = $_script = Path::join(WWW_PATH, 'js'); - $tpl->media = $_media = Path::join(TEMPLATE_WEB, $template); - $tpl->component = $_template = Path::join(COMPONENTS_WEB, strtolower(get_class($this)), 'templates', 'modern'); - $tpl->setAlias(array( - '${media}' => $_media, - '${script}' => $_script, - '${template}' => $_template)); - - $tpl->loadImports(Path::skipExtension($template_file) . ".import"); - - return $tpl; - } - - public function setParameters($view) - { - } - - /** - * @param $name Имя модели - */ - private function getModelPath($name) - { - return Path::join (CMS_PATH, "model", $name . ".php"); - } - - /** - * Создает модель - * @param string $name - * @return model - */ - public function getModel($name) - { - require_once 'core/mapper/mapper.php'; - - require_once ($this->getModelPath ($name)); - $modelName = $name . "Mapper"; - $model = new $modelName (); - $model->db = $this->db; - return $model; - } - - public function options($key, $val, $res) { - $result = array(); - while($res->next()) { - $result[] = array('value' => $res->getInt($key), 'name' => $res->getString($val)); - } - return $result; - } - - public function optionsPair($list) { - $result = array(); - foreach ($list as $key => $value) { - $result [] = array('value' => $key, 'name' => $value); - } - return $result; - } - - /* В дальнейшем нужно зменить на методы - + Методы могут быть и javascript - */ - protected $editUrl; - - function setEditUrl($url) - { - $this->editUrl = $url; - } - - function getEditUrl() - { - return $this->editUrl; - } -} - -/** - * TALES для подключения компонентов - * component:name?param1=value1¶m2=value2 - */ -class Component_Tales implements PHPTAL_Tales -{ - static public function component($expression, $nothrow = false) - { - return "phptal_component('" . $expression . "')"; - } -} - -function loadComponent($name, $db, $registry) -{ - $path = Path::join(COMPONENTS, $name, $name . ".php"); -// echo COMPONENTS, '
'; -// echo $path; - if (file_exists($path)) { - require_once ($path); - $component = new $name(); - $component->db = $db; - $component->_registry = $registry; - $component->viewPath = COMPONENTS."/".$name."/"; - return $component; - } - throw new FileNotFountException(); -} - -/** - * Функция подключения компонента - */ -global $componentList; -$componentList = array(); - -function phptal_component ($real_expression, $offset = 0) { - global $db, $registry, $componentList; // Нужно както передавать параметры - - $expression = htmlspecialchars_decode($real_expression); - $url = parse_url($expression); - parse_str($url['query'], $arguments); - $name = $url['path']; - - $component = loadComponent($name, $db, $registry); - $req = new HttpRequest(); - $params = new Collection(); - $params->import(array_merge($_GET, $arguments)); - $component->params = $params; - - $componentList [] = array( - 'uid' => $component->getUID(), 'params' => $expression, 'name' => $name, 'offset' => $offset, - 'size' => strlen($real_expression), - /* Вместо ссылки на редактирование нужно передавать список методов для работы с компонентом - edit (редактирование содержание), new (новое содержание), шаблон коменнента ... вместе с иконками этих методов - ! Компоненты могут содержать другие компоненты - */ - 'editurl' => $component->getEditUrl(), - 'newurl' => '' - ); - - unset($req['active_page']); - $component->template = $params->get('template', false); - - return $component->execute($params, $req); -} - -/* Регистрация нового префикса для подключения компонента */ -$registry = PHPTAL_TalesRegistry::getInstance(); -$registry->registerPrefix('component', array('Component_Tales', 'component')); - diff --git a/core/controller/controller.php b/core/controller/controller.php deleted file mode 100644 index 5eb13a5..0000000 --- a/core/controller/controller.php +++ /dev/null @@ -1,343 +0,0 @@ -db; - } - - public function installPath($name) - { - return Path::join(CMS_PATH, "modules", $name, "install"); - } - - public function addSuggest($view, $name) - { - $suggest = array(); - $file = Path::join($this->viewPath, 'help', $name . '.suggest'); - if (file_exists($file) && include($file)) { - $view->addScriptRaw("add_suggest(".json::encode($suggest).");\n"); - } - } - - function findIcon($icon, $size) - { - return Path::join($this->iconPath, $size . 'x' . $size, $icon . '.png'); - } - - /** - * Создает представление - * @param string $file - * @return template - */ - public function getView($name) - { - require_once "core/view/compositeview.php"; - - $file = $name . self::TEMPLATE_EXTENSION; - // Список возможных директорий для поиска файла шаблона - $theme = $this->_registry->readKey(array('system', 'theme')); - $icon_theme = $this->_registry->readKey(array('system', 'icon_theme')); - $list = array( - Path::join($this->viewPath, TEMPLATES) => Path::join(WWW_PATH, "modules", $this->name, TEMPLATES), - PHPTAL_TEMPLATE_REPOSITORY => ""); - - - // Поиск файла для шаблона - foreach($list as $ospath => $path) { - $template = Path::join($ospath, $file); - if(file_exists($template)) { break; } - } - - $tpl = new View_Composite($template); - $tpl->icons = $this->iconPath; // Путь к файлам текущей темы - $tpl->media = $this->themePath; // Путь к файлам текущей темы - $tpl->script = $this->jsPath; // Путь к файлам скриптов - $tpl->template = $path; // Путь к файлам текущего шаблона - $tpl->setAlias(array( - '${icons}' => $this->iconPath, - '${media}' => $this->themePath, - '${script}' => $this->jsPath, - '${template}' => $path)); - - $tpl->loadImports(Path::skipExtension($template) . ".import"); - - $this->addSuggest($tpl, $name); - return $tpl; - } - - public function getModel($name) - { - if (!$this->factory) { - $this->factory = new ModelFactory($this->db, $this->_registry, $this->_shortcut); - } - return $this->factory->getModel($name); - } - - /** - * Выбор действия - * Т.к действия являются методами класса то - * 1. Можно переопределить действия - * 2. Использовать наследование чтобы добавить к старому обработчику новое поведение - * @param $request Обьект запроса - */ - public function execute1(HTTPRequest $request) - { - $action = self::ACTION_PREFIX . ucfirst($request->getAction()); - if (method_exists($this, $action)) { - return $this->forward($action, $request); - } else { - return $this->forward("actionIndex", $request); - } - } - - public function execute(HTTPRequest $request) - { - $result = $this->execute1($request); - if ($result) { - $this->view = $result; - } - return $this->render(); - } - - public function forward($action, HTTPRequest $args) - { - // Действия до вызова основного обработчика - /*foreach($this->_aspect as $aspect) { - if (isset($aspect->before[$action])) { - call_user_func ($aspect->before[$action], $action, $args); - } - }*/ - return call_user_func(array($this, $action), $args); - } - - /** - * Страница по умолчанию - */ - public function actionIndex(HttpRequest $request) - { - return ""; - } - - public function postUrl($name, $param) - { - return "?" . http_build_query( - array_merge(array('module' => strtolower(get_class($this)), "action" => $name), - $this->param, $param)); - } - - /** - * Генерация ссылки c учетом прав пользователя на ссылки - * - * @parma string $name Действие - * @parma string $param Дополнительные параметры - */ - public function nUrl($name, array $param = array()) - { - if (!$this->access || $this->access->checkAction($name)) { - return lcurry(array($this, 'postUrl'), $name, $param); - } - return null; - } - - public function fUrl($name, array $param = array()) - { - return forceUrl($this->nUrl($name, $param)); - } - - /** - * Добавляет параметр для всех ссылок создаваемых функцией nUrl, aUrl - */ - public function addParameter($name, $value) - { - if ($value) { - $this->param [$name] = $value; - } - } - - /** - * Генерация ссылки на действие контроллера - * Ajax определяется автоматически mode = ajax используется для смены layout - */ - public function aUrl($name, array $param = array()) - { - return $this->nUrl($name, array_merge(array('mode' => 'ajax'), $param)); // FIXME - } - - /** - * Добавление помошника контроллера - */ - public function addHelper($class) - { - $this->helpers [] = $class; - } - - /** - * Вызов помошников контроллера - */ - public function callHelpers(HttpRequest $request) - { - $action = self::ACTION_PREFIX . $request->getAction(); - foreach ($this->helpers as $helper) { - if (method_exists($helper, $action)) { - return call_user_func(array($helper, $action), $request, $this); - } else { - return $helper->actionIndex($request, $this); // Вместо return response ??? - } - } - } - - /** - * Загрузка файла класса - */ - public function loadClass($path, $setup = null) - { - if (file_exists($path)) { - require_once ($path); - $class = pathinfo($path, PATHINFO_FILENAME); - return new $class($setup); - } - return null; - } - - public function loadSettings($path) - { - $result = new Settings($path); - $result->read(); - return $result->export(); - } - - // Для Widgets - public $view = null; - public $childNodes = array(); - public $childViews = array(); - - public function setView($name) - { - $this->view = $this->getView($name); - } - - /** - * Установка заголовка для отображения - */ - public function setTitle($title) - { - $this->view->setTitle($title); - } - - /** - * Добавление widget к отображению - */ - public function addChild(/*Widget*/ $section, $node) - { - $this->childNodes[$section] = $node; - } - - /** - * Добавление дочернего отображения к текущему отображению - */ - public function addView(/*CompositeView*/ $section, $node) - { - $this->childViews[$section] = $node; - } - - /** - * Генерация содержания - * Путаница c execute и render - */ - public function render() - { - foreach ($this->childNodes as $name => $node) { - $node->make($this); - $this->view->setView($name, $node->view); - } - foreach ($this->childViews as $name => $node) { - $this->view->setView($name, $node); - } - return $this->view; - } - - function getPageId($request) - { - $pageId = time(); - $request->session()->set('page', $pageId); - return $pageId; - } - - function checkPageId($request, $page) - { - $_page = $request->session()->get('page'); - $result = ($_page && $_page == $page); - $request->session()->clean('page'); - return $result; - } - - function redirect($action) { - header('location: ' . $this->fUrl($action)); - exit(); - } -} - -class Controller_Action extends Controller {} - diff --git a/core/data/areas.php b/core/data/areas.php deleted file mode 100644 index a864edf..0000000 --- a/core/data/areas.php +++ /dev/null @@ -1,26 +0,0 @@ - '', - 1 => 'Город Ярославль', - 2 => 'Большесельский район', - 3 => 'Борисоглебский район', - 4 => 'Брейтовский район', - 5 => 'Гаврилов-Ямский район', - 6 => 'Даниловский район', - 7 => 'Любимский район', - 8 => 'Мышкинский район', - 9 => 'Некоузский район', - 10 => 'Некрасовский район', - 11 => 'Переславский район', - 12 => 'Первомайский район', - 13 => 'Пошехонский район', - 14 => 'Ростовский район', - 15 => 'Рыбинский район', - 16 => 'Тутаевский район', - 17 => 'Угличский район', - 18 => 'Ярославский район', - 19 => 'Город Переславль', - 20 => 'Город Рыбинск' -); diff --git a/core/data/city-short.php b/core/data/city-short.php deleted file mode 100644 index bea4476..0000000 --- a/core/data/city-short.php +++ /dev/null @@ -1,14 +0,0 @@ - '', - 1 => 'г.', - 2 => 'с.', - 3 => 'п.', - 4 => 'д.', - 5 => 'пгт.', - 6 => 'р.п.', - 7 => 'ст.', - 8 => 'а.' -); - diff --git a/core/data/city.php b/core/data/city.php deleted file mode 100644 index 5fb0bef..0000000 --- a/core/data/city.php +++ /dev/null @@ -1,14 +0,0 @@ - '', - 1 => 'город', - 2 => 'село', - 3 => 'поселок', - 4 => 'деревня', - 5 => 'поселок городского типа', - 6 => 'рабочий поселок', - 7 => 'станица', - 8 => 'аул' -); diff --git a/core/data/mime.php b/core/data/mime.php deleted file mode 100644 index be65117..0000000 --- a/core/data/mime.php +++ /dev/null @@ -1,196 +0,0 @@ - "application/octet-stream", - "323" => "text/h323", - "acx" => "application/internet-property-stream", - "ai" => "application/postscript", - "aif" => "audio/x-aiff", - "aifc" => "audio/x-aiff", - "aiff" => "audio/x-aiff", - "asf" => "video/x-ms-asf", - "asr" => "video/x-ms-asf", - "asx" => "video/x-ms-asf", - "au" => "audio/basic", - "avi" => "video/x-msvideo", - "axs" => "application/olescript", - "bas" => "text/plain", - "bcpio" => "application/x-bcpio", - "bin" => "application/octet-stream", - "bmp" => "image/bmp", - "c" => "text/plain", - "cat" => "application/vnd.ms-pkiseccat", - "cdf" => "application/x-cdf", - "cer" => "application/x-x509-ca-cert", - "class" => "application/octet-stream", - "clp" => "application/x-msclip", - "cmx" => "image/x-cmx", - "cod" => "image/cis-cod", - "cpio" => "application/x-cpio", - "crd" => "application/x-mscardfile", - "crl" => "application/pkix-crl", - "crt" => "application/x-x509-ca-cert", - "csh" => "application/x-csh", - "css" => "text/css", - "dcr" => "application/x-director", - "der" => "application/x-x509-ca-cert", - "dir" => "application/x-director", - "dll" => "application/x-msdownload", - "dms" => "application/octet-stream", - "doc" => "application/msword", - "dot" => "application/msword", - "dvi" => "application/x-dvi", - "dxr" => "application/x-director", - "eps" => "application/postscript", - "etx" => "text/x-setext", - "evy" => "application/envoy", - "exe" => "application/octet-stream", - "fif" => "application/fractals", - "flr" => "x-world/x-vrml", - "gif" => "image/gif", - "gtar" => "application/x-gtar", - "gz" => "application/x-gzip", - "h" => "text/plain", - "hdf" => "application/x-hdf", - "hlp" => "application/winhlp", - "hqx" => "application/mac-binhex40", - "hta" => "application/hta", - "htc" => "text/x-component", - "htm" => "text/html", - "html" => "text/html", - "htt" => "text/webviewhtml", - "ico" => "image/x-icon", - "ief" => "image/ief", - "iii" => "application/x-iphone", - "ins" => "application/x-internet-signup", - "isp" => "application/x-internet-signup", - "jfif" => "image/pipeg", - "jpe" => "image/jpeg", - "jpeg" => "image/jpeg", - "jpg" => "image/jpeg", - "js" => "application/x-javascript", - "latex" => "application/x-latex", - "lha" => "application/octet-stream", - "lsf" => "video/x-la-asf", - "lsx" => "video/x-la-asf", - "lzh" => "application/octet-stream", - "m13" => "application/x-msmediaview", - "m14" => "application/x-msmediaview", - "m3u" => "audio/x-mpegurl", - "man" => "application/x-troff-man", - "mdb" => "application/x-msaccess", - "me" => "application/x-troff-me", - "mht" => "message/rfc822", - "mhtml" => "message/rfc822", - "mid" => "audio/mid", - "mny" => "application/x-msmoney", - "mov" => "video/quicktime", - "movie" => "video/x-sgi-movie", - "mp2" => "video/mpeg", - "mp3" => "audio/mpeg", - "mpa" => "video/mpeg", - "mpe" => "video/mpeg", - "mpeg" => "video/mpeg", - "mpg" => "video/mpeg", - "mpp" => "application/vnd.ms-project", - "mpv2" => "video/mpeg", - "ms" => "application/x-troff-ms", - "mvb" => "application/x-msmediaview", - "nws" => "message/rfc822", - "oda" => "application/oda", - "p10" => "application/pkcs10", - "p12" => "application/x-pkcs12", - "p7b" => "application/x-pkcs7-certificates", - "p7c" => "application/x-pkcs7-mime", - "p7m" => "application/x-pkcs7-mime", - "p7r" => "application/x-pkcs7-certreqresp", - "p7s" => "application/x-pkcs7-signature", - "pbm" => "image/x-portable-bitmap", - "pdf" => "application/pdf", - "pfx" => "application/x-pkcs12", - "pgm" => "image/x-portable-graymap", - "pko" => "application/ynd.ms-pkipko", - "pma" => "application/x-perfmon", - "pmc" => "application/x-perfmon", - "pml" => "application/x-perfmon", - "pmr" => "application/x-perfmon", - "pmw" => "application/x-perfmon", - "pnm" => "image/x-portable-anymap", - "pot," => "application/vnd.ms-powerpoint", - "ppm" => "image/x-portable-pixmap", - "pps" => "application/vnd.ms-powerpoint", - "ppt" => "application/vnd.ms-powerpoint", - "prf" => "application/pics-rules", - "ps" => "application/postscript", - "pub" => "application/x-mspublisher", - "qt" => "video/quicktime", - "ra" => "audio/x-pn-realaudio", - "ram" => "audio/x-pn-realaudio", - "ras" => "image/x-cmu-raster", - "rgb" => "image/x-rgb", - "rmi" => "audio/mid", - "roff" => "application/x-troff", - "rtf" => "application/rtf", - "rtx" => "text/richtext", - "scd" => "application/x-msschedule", - "sct" => "text/scriptlet", - "setpay" => "application/set-payment-initiation", - "setreg" => "application/set-registration-initiation", - "sh" => "application/x-sh", - "shar" => "application/x-shar", - "sit" => "application/x-stuffit", - "snd" => "audio/basic", - "spc" => "application/x-pkcs7-certificates", - "spl" => "application/futuresplash", - "src" => "application/x-wais-source", - "sst" => "application/vnd.ms-pkicertstore", - "stl" => "application/vnd.ms-pkistl", - "stm" => "text/html", - "svg" => "image/svg+xml", - "sv4cpio" => "application/x-sv4cpio", - "sv4crc" => "application/x-sv4crc", - "swf" => "application/x-shockwave-flash", - "t" => "application/x-troff", - "tar" => "application/x-tar", - "tcl" => "application/x-tcl", - "tex" => "application/x-tex", - "texi" => "application/x-texinfo", - "texinfo" => "application/x-texinfo", - "tgz" => "application/x-compressed", - "tif" => "image/tiff", - "tiff" => "image/tiff", - "tr" => "application/x-troff", - "trm" => "application/x-msterminal", - "tsv" => "text/tab-separated-values", - "txt" => "text/plain", - "uls" => "text/iuls", - "ustar" => "application/x-ustar", - "vcf" => "text/x-vcard", - "vrml" => "x-world/x-vrml", - "wav" => "audio/x-wav", - "wcm" => "application/vnd.ms-works", - "wdb" => "application/vnd.ms-works", - "wks" => "application/vnd.ms-works", - "wmf" => "application/x-msmetafile", - "wps" => "application/vnd.ms-works", - "wri" => "application/x-mswrite", - "wrl" => "x-world/x-vrml", - "wrz" => "x-world/x-vrml", - "xaf" => "x-world/x-vrml", - "xbm" => "image/x-xbitmap", - "xla" => "application/vnd.ms-excel", - "xlc" => "application/vnd.ms-excel", - "xlm" => "application/vnd.ms-excel", - "xls" => "application/vnd.ms-excel", - "xlt" => "application/vnd.ms-excel", - "xlw" => "application/vnd.ms-excel", - "xof" => "x-world/x-vrml", - "xpm" => "image/x-xpixmap", - "xwd" => "image/x-xwindowdump", - "z" => "application/x-compress", - "zip" => "application/zip", -); - diff --git a/core/data/okato.php b/core/data/okato.php deleted file mode 100644 index a066e66..0000000 --- a/core/data/okato.php +++ /dev/null @@ -1,35 +0,0 @@ - "район", - "г" => "город", - "пгт" => "поселок городского типа", - "рп" => "рабочий поселок", - "кп" => "курортный поселок", - "к" => "кишлак", - "пс" => "поселковый совет", - "сс" => "сельсовет", - "смн" => "сомон", - "вл" => "волость", - "дп" => "дачный поселковый совет", - "п" => "поселок сельского типа", - "нп" => "населенный пункт", - "п. ст" => "поселок при станции", - "ж/д ст" => "железнодорожная станция", - "с" => "село", - "м" => "местечко", - "д" => "деревня", - "сл" => "слобода", - "ст" => "станция", - "ст-ца" => "станица", - "х" => "хутор", - "у" => "улус", - "рзд" => "разъезд", - "клх" => "колхоз", - "им" => "имени", - "свх" => "совхоз", - "зим" => "зимовье", -); - diff --git a/core/data/regions.php b/core/data/regions.php deleted file mode 100644 index e2fb520..0000000 --- a/core/data/regions.php +++ /dev/null @@ -1,91 +0,0 @@ - '', - 2 => 'Алтайский край', - 3 => 'Амурская область', - 4 => 'Архангельская область', - 5 => 'Астраханская область', - 6 => 'Белгородская область', - 7 => 'Брянская область', - 8 => 'Владимирская область', - 9 => 'Волгоградская область', - 10 => 'Вологодская область', - 11 => 'Воронежская область', - 12 => 'г. Москва', - 13 => 'г. Санкт-Петербург', - 14 => 'Еврейская автономная область', - 84 => 'Забайкальский край', - 15 => 'Ивановская область', - 16 => 'Иркутская область', - 17 => 'Кабардино-Балкарская Республика', - 18 => 'Калининградская область', - 19 => 'Калужская область', - 20 => 'Камчатский край', - 21 => 'Карачаево-Черкесская Республика', - 22 => 'Кемеровская область', - 23 => 'Кировская область', - 28 => 'Костромская область', - 29 => 'Краснодарский край', - 30 => 'Красноярский край', - 31 => 'Курганская область', - 32 => 'Курская область', - 33 => 'Ленинградская область', - 34 => 'Липецкая область', - 35 => 'Магаданская область', - 36 => 'Московская область', - 37 => 'Мурманская область', - 38 => 'Ненецкий автономный округ', - 39 => 'Нижегородская область', - 40 => 'Новгородская область', - 41 => 'Новосибирская область', - 42 => 'Омская область', - 43 => 'Оренбургская область', - 44 => 'Орловская область', - 45 => 'Пензенская область', - 46 => 'Пермский край', - 47 => 'Приморский край', - 48 => 'Псковская область', - 49 => 'Республика Адыгея', - 50 => 'Республика Алтай', - 51 => 'Республика Башкортостан', - 52 => 'Республика Бурятия', - 25 => 'Республика Дагестан', - 26 => 'Республика Ингушетия', - 53 => 'Республика Калмыкия', - 54 => 'Республика Карелия', - 55 => 'Республика Коми', - 56 => 'Республика Марий Эл', - 57 => 'Республика Мордовия', - 58 => 'Республика Саха(Якутия)', - 59 => 'Республика Северная Осетия-Алания', - 60 => 'Республика Татарстан', - 61 => 'Республика Тыва', - 62 => 'Республика Хакасия', - 63 => 'Ростовская область', - 64 => 'Рязанская область', - 65 => 'Самарская область', - 66 => 'Саратовская область', - 67 => 'Сахалинская область', - 68 => 'Свердловская область', - 69 => 'Смоленская область', - 70 => 'Ставропольский край', - 71 => 'Таймырский (Долгано-Ненецкий) автономный округ', - 72 => 'Тамбовская область', - 73 => 'Тверская область', - 74 => 'Томская область', - 75 => 'Тульская область', - 76 => 'Тюменская область', - 77 => 'Удмуртская Республика', - 78 => 'Ульяновская область', - 80 => 'Хабаровский край', - 81 => 'Ханты-Мансийский автономный округ', - 82 => 'Челябинская область', - 83 => 'Чеченская Республика', - 85 => 'Чувашская Республика', - 86 => 'Чукотский автономный округ', - 87 => 'Эвенкийский автономный округ', - 88 => 'Ямало-Ненецкий автономный округ', - 89 => 'Ярославская область' -); - diff --git a/core/data/states.php b/core/data/states.php deleted file mode 100644 index 346cae4..0000000 --- a/core/data/states.php +++ /dev/null @@ -1,32 +0,0 @@ - array('title' => ''), - 1 => array( - 'title' => 'Центральный федеральный округ', - 'short' => 'ЦФО', - 'regions' => array(6, 7, 8, 11, 12, 15, 19, 28, 32, 34, 36, 44, 64, 69, 72, 73, 75, 89)), - 2 => array( - 'title' => 'Южный федеральный округ', - 'short' => 'ЮФО', - 'regions' => array(5, 9, 17, 21, 29, 49, 25, 26, 53, 59, 63, 70, 83)), - 3 => array( - 'title' => 'Северо-западный федеральный округ', - 'short' => 'СЗФО', - 'regions' => array(4, 10, 13, 18, 33, 37, 38, 40, 48, 54, 55)), - 4 => array( - 'title' => 'Дальневосточный федеральный округ', - 'short' => 'ДФО', - 'regions' => array(3, 14, 20, 35, 47, 58, 67, 80, 86)), - 5 => array( - 'title' => 'Сибирский федеральный округ', - 'short' => 'СФО', - 'regions' => array(2, 16, 22, 30, 41, 42, 50, 52, 61, 62, 71, 74, 84, 86, 87)), - 6 => array( - 'title' => 'Уральский федеральный округ', - 'short' => 'УФО', - 'regions' => array(31, 68, 76, 81, 82, 88)), - 7 => array( - 'title' => 'Приволжский федеральный округ', - 'short' => 'ПФО', - 'regions' => array(23, 39, 43, 45, 46, 51, 56, 57, 60, 65, 66, 77, 78, 85))); diff --git a/core/database.php b/core/database.php deleted file mode 100644 index 52eca1a..0000000 --- a/core/database.php +++ /dev/null @@ -1,16 +0,0 @@ -connect($dsn); - return $database; - } -} diff --git a/core/database_pdo.php b/core/database_pdo.php deleted file mode 100644 index f8db49c..0000000 --- a/core/database_pdo.php +++ /dev/null @@ -1,407 +0,0 @@ -setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDODatabaseStatement', array())); - } - - public function getDSN() - { - return $this->dsn; - } - - public function isPostgres(){ - return ($this->dsn["phptype"] == "pgsql"); - } - /** - * Создает соединение с базой данных - */ - static function getConnection(array $dsn) - { - if ($dsn['phptype'] == 'pgsql' || $dsn['phptype'] == 'mysql') { - $port = (isset($dsn['port'])) ? "port={$dsn['port']};" : ""; - $connection = new Database("{$dsn['phptype']}:host={$dsn['hostspec']}; $port dbname={$dsn['database']}", $dsn['username'], $dsn['password']); - $connection->query('SET client_encoding = "UTF-8"'); - } - if ($dsn['phptype'] == 'sqlite') { - $connection = new Database("{$dsn['phptype']}:{$dsn['database']}"); - } - $connection->dsn = $dsn; - return $connection; - } - - public function executeQuery($query) - { - $stmt = $this->prepare($query); - $stmt->setFetchMode(PDO::FETCH_ASSOC); - $stmt->execute(); - $stmt->cache = $stmt->fetchAll(); - return $stmt;//$sth->fetchAll(); - } - - public function prepareStatement($query) - { - return new DatabaseStatement($query, $this); - } - - // Для совместимости со старым представлением баз данных CIS - /** - * Извлекает из базы все элементы по запросу - */ - public function fetchAllArray($query,$values=null) - { - $sth = $this->prepare($query); - $prep = $this->prepareValues($values); - $sth->execute($prep); - return $sth->fetchAll(PDO::FETCH_ASSOC); - } - - /** - * Извлекает из базы первый элемент по запросу - */ - public function fetchOneArray($query,$values=null) - { - $sth = $this->prepare($query); - $prep = $this->prepareValues($values); - $sth->execute($prep); - return $sth->fetch(PDO::FETCH_ASSOC); - } - - private function assignQuote($x, $y) - { - return $x . "=" . $this->quote($y); - } - - private function prepareValues($values) - { - if (!$values) { - return null; - } - $pg = $this->isPostgres(); - $prep = array(); - foreach ($values as $key => $value) { - $result = null; - if(is_bool($value)) { - if ($pg) { - $result = $value ? 'true' : 'false'; - } else { - $result = $value ? 1 : 0; - } - } else { - $result = $value; - } - $prep[":" . $key] = $result; - } - return $prep; - } - /** - * Создает INSERT запрос - */ - function insertQuery($table, array $values, $return_id = false, $index = null) - { - $prep = $this->prepareValues($values); - - $sql = "INSERT INTO $table (" . implode(",", array_keys($values)) - . ") VALUES (" . implode(",", array_keys($prep)). ")"; - - if($return_id){ - if ($this->isPostgres()){ - $sql = $sql." RETURNING $index"; - } - } - $stmt = $this->prepare($sql); - $stmt->setFetchMode(PDO::FETCH_ASSOC); - $stmt->execute($prep); - $result = $stmt->fetch(); - if ($return_id) { - if ($this->isPostgres()) { - return $result[$index]; - } else { - $result = $this->fetchOneArray("SELECT $index AS lastid FROM $table WHERE OID = last_insert_rowid()"); - return $result['lastid']; - } - } - } - - /** - * Создает UPDATE запрос - */ - function updateQuery($table, array $values, $cond) - { - return $this->query("UPDATE $table SET " . implode(",", - array_map(array($this, 'assignQuote'), array_keys($values), array_values($values))) . " WHERE $cond"); - } - - function getIdGenerator() { - return new IdGenerator($this); - } - - /** - * Замечание: Только для Postgres SQL - * @param string $seq Имя последовательности для ключа таблицы - * @return int Идентефикатор следующей записи - */ - function getNextId($seq) - { - $result = $this->fetchOneArray("SELECT nextval('$seq')"); - return $result['nextval']; - } - - function close() - { - return null; - } -} - -class IdGenerator { - private $db; - - function __construct($db) { - $this->db = $db; - } - - function isBeforeInsert() { - return false; - } - - function isAfterInsert() { - return true; - } - - function getId($seq) { - $result = $this->db->fetchOneArray("SELECT nextval('$seq')"); - return $result['nextval']; -// $result = $this->db->fetchOneArray("SELECT last_insert_rowid() AS nextval"); -// return $result['nextval']; - } -} - -class PDODatabaseStatementIterator implements Iterator -{ - - private $result; - private $pos = 0; - private $fetchmode; - private $row_count; - private $rs; - - - /** - * Construct the iterator. - * @param PgSQLResultSet $rs - */ - public function __construct($rs) - { - $this->result = $rs; - $this->row_count = $rs->getRecordCount(); - } - - function rewind() - { - $this->pos = 0; - } - - function valid() - { - return ($this->pos < $this->row_count); - } - - function key() - { - return $this->pos; - } - - function current() - { - if (!isset($this->result->cache[$this->pos])) { - $this->result->cache[$this->pos] = $this->result->fetch(PDO::FETCH_ASSOC); - } - return $this->result->cache[$this->pos]; - } - - function next() - { - $this->pos++; - } - - function seek ( $index ) - { - $this->pos = $index; - } - - function count ( ) { - return $this->row_count; - } -} - -class PDODatabaseStatement extends PDOStatement implements IteratorAggregate -{ - protected $cursorPos = 0; - public $cache = array(); - - function getIterator() - { - return new PDODatabaseStatementIterator($this); - } - - protected function __construct() { - } - - function rewind() - { - $this->cursorPos = 0; - } - - public function seek($rownum) - { - if ($rownum < 0) { - return false; - } - - // PostgreSQL rows start w/ 0, but this works, because we are - // looking to move the position _before_ the next desired position - $this->cursorPos = $rownum; - return true; - } - - function valid() - { - return ( true ); - } - - - public function first() - { - if($this->cursorPos !== 0) { $this->seek(0); } - return $this->next(); - } - - function next() - { - if ($this->getRecordCount() > $this->cursorPos) { - if (!isset($this->cache[$this->cursorPos])) { - $this->cache[$this->cursorPos] = $this->fetch(PDO::FETCH_ASSOC); - } - $this->fields = $this->cache[$this->cursorPos]; - - $this->cursorPos++; - return true; - } else { - $this->fields = null; - return false; - } - } - - function key() { - return $this->cursorPos; - } - - function current() - { - return $this->result->fetch(PDO::FETCH_ASSOC); - } - - function getRow() - { - return $this->fields; - } - - function getInt($name) - { - return intval($this->fields[$name]); - } - - function getBlob($name) - { - return $this->fields[$name]; - } - - function getString($name) - { - return $this->fields[$name]; - } - - function getBoolean($name) - { - return (bool)$this->fields[$name]; - } - - function get($name) - { - return $this->fields[$name]; - } - - function getRecordCount() - { - return count($this->cache); - } -} - - -/** - * Класс оболочка для PDOStatement для замены Creole - */ -class DatabaseStatement -{ - protected $limit = null; - protected $offset = null; - protected $statement = null; - protected $binds = array(); - protected $conn; - protected $query; - - function __construct($query, $conn) { - $this->query = $query; - $this->conn = $conn; - } - - function setInt($n, $value) - { - $this->binds [] = array($n, $value, PDO::PARAM_INT); - } - - function setString($n, $value) - { - $this->binds [] = array($n, $value, PDO::PARAM_STR); - } - - function setBlob($n, $value) - { - $this->binds [] = array($n, $value, PDO::PARAM_LOB); - } - - function setLimit($limit) - { - $this->limit = $limit; - } - - function setOffset($offset) - { - $this->offset = $offset; - } - - function executeQuery() - { - if ($this->limit) { - $this->query .= " LIMIT {$this->limit} OFFSET {$this->offset}"; - } - $stmt = $this->conn->prepare($this->query); - foreach ($this->binds as $bind) { - list($n, $value, $type) = $bind; - $stmt->bindValue($n, $value, $type); - } - $stmt->setFetchMode(PDO::FETCH_ASSOC); - $stmt->execute(); - $stmt->cache = $stmt->fetchAll(); - - return $stmt; - } -} diff --git a/core/drivers/database.mysql.php b/core/drivers/database.mysql.php deleted file mode 100644 index 99eb601..0000000 --- a/core/drivers/database.mysql.php +++ /dev/null @@ -1,50 +0,0 @@ -db = $db); - } - - public function close() - { - return mysql_close($this->db); - } - - public function query($query) - { - $res = mysql_query($this->db, $query) - or die("Error: wrong SQL query #$query#"); - return $res; - } - - public function fetchAllArray($query) - { - $res = $this->query($query); - - while ($row = mysql_fetch_array ($res)) - $rows[] = $row; - mysql_free_result($res); - return ($rows) ? $rows : array(); - } - - public function fetchOneArray($query) - { - $res = $this->query($query); - $row = mysql_fetch_array($res); - mysql_free_result($res); - return ($row) ? $row : array(); - } -} - -?> \ No newline at end of file diff --git a/core/drivers/database.odbc.php b/core/drivers/database.odbc.php deleted file mode 100644 index cb166bf..0000000 --- a/core/drivers/database.odbc.php +++ /dev/null @@ -1,54 +0,0 @@ -db = $db); - } - - public function close() - { - return odbc_close($this->db); - } - - public function query($query) - { - $res = odbc_exec($this->db, $query) - or die("Error: wrong SQL query #$query#"); - return $res; - } - - public function fetchAllArray($query) - { - $res = $this->query($query); - $to = odbc_num_fields($res); - while (odbc_fetch_row($res)) { - for ($i = 1; $i <= $to; $i++) { - $row [odbc_field_name($res, $i)] = trim(odbc_result($res, $i)); - } - $rows[] = $row; - } - return ($rows)? $rows : array(); - } - - public function fetchOneArray($query) - { - $res = $this->query($query); - if (!odbc_fetch_row($res)) return array (); - $to = odbc_num_fields($res); - for ($i = 1; $i <= $to; $i++) { - $row [odbc_field_name($res, $i)] = trim(odbc_result($res, $i)); - } - return $row; - } -} - -?> \ No newline at end of file diff --git a/core/drivers/database.pgsql.php b/core/drivers/database.pgsql.php deleted file mode 100644 index 64de93f..0000000 --- a/core/drivers/database.pgsql.php +++ /dev/null @@ -1,74 +0,0 @@ -db = $db); - } - - public function close() - { - return pg_close($this->db); - } - - public function query($query) - { - $res = pg_query($this->db, $query) - or die("Error: wrong SQL query #$query#"); - return $res; - } - - public function fetchAllArray($query, $type = PGSQL_ASSOC) - { - $res = $this->query($query); - - $rows = array(); - while ($row = pg_fetch_array($res, NULL, $type)) { - $rows[] = $this->clean($row); - } - pg_free_result($res); - return ($rows) ? $rows : array(); - } - - public function affectedRows() - { - return pg_affected_rows($this->db); - } - - private function clean($row) - { - foreach ($row as $key => $value) { - $row[$key] = trim($value); - } - return $row; - } - - public function fetchOneArray($query, $type = PGSQL_ASSOC) - { - $res = $this->query($query); - $row = pg_fetch_array($res, NULL, $type); - pg_free_result($res); - return ($row) ? $this->clean($row) : array(); - } - - function getNextId($seq) - { - $result = $this->fetchOneArray("SELECT nextval('$seq')"); - return $result['nextval']; - } -} diff --git a/core/drivers/db.php b/core/drivers/db.php deleted file mode 100644 index 3e5014d..0000000 --- a/core/drivers/db.php +++ /dev/null @@ -1,50 +0,0 @@ -query("INSERT INTO $table (" . implode(",", array_keys($values)) - . ") VALUES (" . implode(",", array_map(array('self', 'quote'), array_values($values))) . ")"); - } - - function update($table, array $values, $cond) - { - return $this->query("UPDATE $table SET " . implode(",", - array_map(array('self', 'assign_quote'), array_keys($values), array_values($values))) . " WHERE $cond"); - } - - function check_text($text) - { - if(strlen($text) > self::limit) $text = substr($text, 0, self::limit); - $text = htmlspecialchars(trim($text)); - return $text; - } -} - -?> \ No newline at end of file diff --git a/core/error.php b/core/error.php deleted file mode 100644 index de256bb..0000000 --- a/core/error.php +++ /dev/null @@ -1,86 +0,0 @@ - 'E_ERROR', - 2 => 'E_WARNING', - 4 => 'E_PARSE', - 8 => 'E_NOTICE', - 16 => 'E_CORE_ERROR', - 32 => 'E_CORE_WARNING', - 64 => 'E_COMPILE_ERROR', - 128 => 'E_COMPILE_WARNING', - 256 => 'E_USER_ERROR', - 512 => 'E_USER_WARNING', - 1024 => 'E_USER_NOTICE', - 2048 => 'E_STRICT', - 4096 => 'E_RECOVERABLE_ERROR', - 8192 => 'E_DEPRECATED', - 16384 => 'E_USER_DEPRECATED', - 30719 => 'E_ALL'); - return $names[$id]; -} - - -function send_error($description) { - $message = "request: " . "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] . "\n"; - $message .= "from: " . $_SERVER['REMOTE_ADDR'] . "\n"; - if(isset($_SERVER['HTTP_REFERER'])) $message .= "referer: " . $_SERVER['HTTP_REFERER'] . "\n"; - $message .= "post:" . var_export($_POST, true) . "\n"; - $message .= "description: " . $description; - -// error_log($message, ERROR_TYPE, ERROR_FILE); - return false; -} - -function error_handler($errno, $errstr, $errfile, $errline) { - $message = "request: " . "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] . "\n"; - $message .= "from: " . $_SERVER['REMOTE_ADDR'] . "\n"; - if(isset($_SERVER['HTTP_REFERER'])) $message .= "referer: " . $_SERVER['HTTP_REFERER'] . "\n"; - $message .= "post:" . var_export($_POST, true) . "\n"; - $message .= "type: " . get_error_name($errno) . "\n" - . "error: " . $errstr . "\n" - . "line: " . $errline . "\n" - . "file: " . $errfile; - -// error_log($message, ERROR_TYPE, ERROR_FILE); - return false; -} - -function shutdown() { - $error = error_get_last(); - $message = "request: " . "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] . "\n"; - $message .= "from: " . $_SERVER['REMOTE_ADDR'] . "\n"; - if(isset($_SERVER['HTTP_REFERER'])) $message .= "referer: " . $_SERVER['HTTP_REFERER'] . "\n"; - if (is_array($error)) { - foreach ($error as $info => $string) { - $message .= "{$info}: {$string}\n"; - } - } - - error_log($message, ERROR_TYPE, ERROR_FILE); -} - -function exception_handler($exception) { - $message = "request: " . "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] . "\n"; - $message .= "from: " . $_SERVER['REMOTE_ADDR'] . "\n"; - if(isset($_SERVER['HTTP_REFERER'])) $message .= "referer: " . $_SERVER['HTTP_REFERER'] . "\n"; - $message .= - "file: " . $exception->getFile() . "\n" - . "line: " . $exception->getLine() . "\n" - . "message: " . $exception->getMessage() . "\n" - . "trace: " . $exception->getTraceAsString(); - error_log($message, ERROR_TYPE, ERROR_FILE); - return true; -} - -set_exception_handler('exception_handler'); -set_error_handler("error_handler"); -//register_shutdown_function('shutdown'); diff --git a/core/file.php b/core/file.php deleted file mode 100644 index abad27a..0000000 --- a/core/file.php +++ /dev/null @@ -1,80 +0,0 @@ -file = $file; - $this->filename = $src; - $this->parent = $parent; - } - - function get($name) { - return isset($this->file[$name]) ? $this->file[$name] : null; - } - - function fileStat() - { - $type = is_dir($this->filename); - return array( - 'name' => ($this->parent) ? ".." : $this->getName(), - 'type' => $type, - 'extension' => ($type) ? 'folder' : pathinfo($this->filename, PATHINFO_EXTENSION), - 'date' => date("d.m.Y H:i", $this->getTime()), - 'access' => 0, - 'size' => ($type) ? "" : $this->getSizeString(), - 'state' => isset($this->file['state']) ? $this->file['state'] : 'unknown', - 'title' => $this->getTitle(), - /*'author' => $this->file['author'], - 'description' => $this->file['description'], - 'keywords' => $this->file['keywords'],*/ - ); - } - - function isExpected() - { - if (isset($this->file['state'])) { - return ($this->file['state'] == 'expected'); - } - return false; - } - - function getSizeString() - { - $size = $this->getSize(); - foreach (array('б ', 'Kб', 'Mб') as $suffix) { - if (($size / 1024) <= 1) { - return round($size, 0) . ' ' . $suffix; - } - $size /= 1024; - } - return round($size, 0) . ' GB'; - } - - function getSize() - { - return ($this->isExpected()) ? 0 : filesize($this->filename); - } - - function getTime() - { - return ($this->isExpected()) ? 0 : filemtime($this->filename); - } - - function getName() - { - return pathinfo($this->filename, PATHINFO_BASENAME); - } - - function getTitle() - { - return isset($this->file['title']) ? $this->file['title'] : $this->getName(); - } -} diff --git a/core/filter/filterlogin.php b/core/filter/filterlogin.php deleted file mode 100644 index 1ed835a..0000000 --- a/core/filter/filterlogin.php +++ /dev/null @@ -1,105 +0,0 @@ -getConnection(); - UserAccess::setUp($db); // Соединение - switch ($request->getAction()) { - // Авторизация по постоянному паролю - case 'login': - $login = $request->get('login'); - $password = $request->get('password'); - - $result = UserAccess::getUserByLogin($login); // Поиск по логину - if ($result) { - if (md5($password) == $result->getString('password')) { // password - $this->enter($db, $result); - return true; - } - } - $request->set('error', true); - break; - case 'logout': // Выход - session_destroy(); - break; - // Вход по временному паролю - case 'enter': - $login = $request->get('login'); - $password = $request->get('sid'); - $result = UserAccess::getUserByLogin($login); // Поиск по логину - if ($result) { - $temp = md5($result->getString('password') . $result->getString('login') . $result->getString('sid')); - if ($password == $temp) { - $this->enter($db, $result); - return true; - } - } - break; - default: - $hash = $this->getBrowserSign(); - // Если $hash не совпадает $_SESSION['hash'] то удаляем сессию - if (isset($_SESSION ['access']) && isset($_SESSION[self::SESSION_BROWSER_SIGN_SECRET])) { - if ($hash == $_SESSION[self::SESSION_BROWSER_SIGN_SECRET]) { - UserAccess::getUserById($_SESSION ['access']); // Поиск по идентификатору - return true; - } else { - session_destroy(); - } - } - } - return false; - } - - private function getBrowserSign() - { - $rawSign = self::SESSION_BROWSER_SIGN_SECRET; - $signParts = array('HTTP_USER_AGENT', 'HTTP_ACCEPT_ENCODING'); - - $rawSign = ''; - foreach ($signParts as $signPart) { - $rawSign .= '::' . (isset($_SERVER[$signPart]) ? $_SERVER[$signPart] : 'none'); - } - return md5($rawSign); - } - - private function enter($db, $result) - { - $db->executeQuery("UPDATE users SET sid = '' WHERE id_user = " . $result->getInt('id_user')); - - $_SESSION ["group"] = $result->getInt('access'); - $_SESSION ["access"] = $result->getInt('id_user'); // id_user - $_SESSION [self::SESSION_BROWSER_SIGN_SECRET] = $this->getBrowserSign(); - $_SESSION ["time"] = time(); - } - - public function execute(HttpRequest $request) - { - if (!$this->isLoggin($request)) { - // Параметры при неправильной авторизации - // Действия по умолчанию !! Возможно переход на форму регистрации - $request->set('module', 'login'); - $request->set('mode', $this->mode); - } - return $this->processor->execute($request); - } -} - diff --git a/core/form/form.php b/core/form/form.php deleted file mode 100644 index bd0ddd6..0000000 --- a/core/form/form.php +++ /dev/null @@ -1,178 +0,0 @@ -deafult = null; - if (isset($input['validate'])) { - $this->require = strpos($input['validate'], 'require') !== false; - } - // Инициализация свойст обьетка - foreach (array('label', 'name', 'type') as $name) { - $this->$name = $input[$name]; - } - } - - function setValue($value) - { - $this->value = $value; - } -} - -/** - * Поле ввода Input - * @package core - */ -class TInput extends TField { -} - -/** - * Выбор из одного элемента - */ -class TSelect1 extends TField -{ - public $options = array (); - public function __construct ($input) { - parent::__construct($input); - $this->options = $input['options']; - } - - function setValue($value) - { - // Установить selected у options - $this->value = $value; - } -} - -/** - * Поле с датой - * @package core - */ -class TDate extends TField -{ -} - -/* * - * Текстовое поле - * @package core - */ -class TTextArea extends TField -{ -} - -/** - * Поле для ввода пароля - * @package core - */ -class TSecret extends TField -{ -} - -class TUpload extends TField -{ -} - -/** - * Форма для ввода - * @package core - */ -class TForm -{ - public $field = array (); - public $action = ""; - public $method = 'post'; - protected $replace; - protected $before; - - public function __construct () - { - $this->constructor = array ( - 'input' => 'TInput', - 'date' => 'TDate', - 'textarea' => 'TTextArea', - 'select' => 'TSelect', - 'select1' => 'TSelect1', - 'secret' => 'TSecret', - 'upload' => 'TUpload' - ); - } - - /** - * Добавляет одно поле ввода на форму - */ - public function addField (array $init) - { - assert (isset($init['type'])); - assert (isset($init['name'])); - - $constructor = $this->constructor[$init['type']]; - $el = new $constructor ($init); - $el->type = $init['type']; - - $this->field [$init['name']] = $el; - return $el; - } - - /** - * Добавляет спсок полей для формы - * @param array $list - */ - public function addFieldList (array $list) - { - foreach ($list as $init) { - $this->addField ($init); - } - } - - /** - * Устанавливает ошибки после проверки - */ - function setError (Validator $validator) - { - foreach ($validator->getErrorMsg() as $name => $error) - { - $this->field[$name]->error = true; - $this->field[$name]->error_msg = $error; - } - } - - /** - * Устанавливает значения из масива - */ - function setValues (Collection $request) { - foreach ($this->field as $key => $el) { - $value = $request->getRawData ($this->method, $key); - $this->field[$key]->setValue($value); - } - } - - /** - * Заполняет форму данными из обьекта - * @param object $data - * @param array $schema Связь между элементами формы и свойствами обьекта - */ - public function fill ($data, array $schema) - { - foreach ($schema as $key => $value) { - $this->field [$value]->setValue($data->$value->getString ()); - } - } - - public function set($name, $value) - { - $this->field[$name]->setValue($value); - } -} diff --git a/core/formats/dot.php b/core/formats/dot.php deleted file mode 100644 index 3c57d3b..0000000 --- a/core/formats/dot.php +++ /dev/null @@ -1,52 +0,0 @@ - $value) { - foreach ($value as $n) { - $result [] = "\t\"$key\" -> \"$n\"\n"; - } - } - $result [] = self::getFooter(); - return implode("", $result); - } -} - -?> \ No newline at end of file diff --git a/core/formats/helix.php b/core/formats/helix.php deleted file mode 100644 index ff52c53..0000000 --- a/core/formats/helix.php +++ /dev/null @@ -1,85 +0,0 @@ -uuid = "*"; - $this->uuid_writeable = 1; - } - - public function getString () { - return "{$this->password};{$this->uuid};{$this->uuid_writeable}"; - } - - public function setPassword ($username, $realm, $password) { - $this->password = md5 ("$username:$realm:$password"); - } -} - -class HPermission { - public $url; - public $url_type; - public $permission_type; - public $expires; - public $debitted_time; - - public function __construct ($url, $url_type) { - $this->url = $url; - $this->url_type = $url_type; - $this->expires = "*"; // MM/DD/YYYY:HH:MM:SS - $this->permission_type = 0; - $this->debitted_time = 0; - } - - public function getString () { - return "{$this->url};{$this->url_type};{$this->permission_type};{$this->expires};{$this->debitted_time}"; - } -} - -class HFile { - public $authorize; - public $permission = array (); - - public function addAuthorize ($name, $realm, $password) { - $this->authorize = new HAuthorize (); - $this->authorize->setPassword ($name, $realm, $password); - } - - public function addPermission ($url, $url_type) { - $this->permission[] = new HPermission ($url, $url_type); - } - - public function write ($name) { - $file = fopen ($name, 'w'); - fwrite ($file, $this->getString ()); - fclose ($file); - } - - public function writeFTP ($ftp, $path) { - $file = tmpfile (); - fwrite ($file, $this->getString ()); - fseek ($file, 0); - - ftp_fput ($ftp, $path, $file, FTP_BINARY); - - fclose ($file); - } - - public function getString () { - $result = array (); - $result[] = $this->authorize->getString (); - $result[] = "\n"; - foreach ($this->permission as $p) { - $result[] = $p->getString (); - $result[] = "\n"; - } - return implode ("", $result); - } -} - diff --git a/core/geometry/point.php b/core/geometry/point.php deleted file mode 100644 index 61254e6..0000000 --- a/core/geometry/point.php +++ /dev/null @@ -1,12 +0,0 @@ -left = $left; - $this->top = $top; - } -} - diff --git a/core/geometry/rectangle.php b/core/geometry/rectangle.php deleted file mode 100644 index 4c7c0e0..0000000 --- a/core/geometry/rectangle.php +++ /dev/null @@ -1,51 +0,0 @@ -left = $left; - $this->top = $top; - $this->width = $width; - $this->height = $height; - } - - function __get($name) - { - switch ($name) { - case 'right': return $this->left + $this->width; - case 'bottom': return $this->top + $this->height; - } - } - - function __set($name, $value) - { - switch ($name) { - case 'right': $this->width = $value - $this->left; - case 'bottom': $this->height = $value - $this->top; - } - } - - /** - * Смещает прямоугольник на заданное положение - */ - function addPoint(Point $point) - { - $result = clone $this; - $result->left += $point->left; - $result->top += $point->top; - return $result; - } - - /** - * Координаты точки при выравнивании прямоугольника относительно текущего - */ - function alignment(Rectangle $base) - { - return new Point((($base->left + $base->right) - ($this->left + $this->right)) / 2, $base->bottom - $this->height); - } -} diff --git a/core/mapper/factory.php b/core/mapper/factory.php deleted file mode 100644 index d3dbe87..0000000 --- a/core/mapper/factory.php +++ /dev/null @@ -1,28 +0,0 @@ -db = $db; - } - - /** - * Создает модель - * @param string $name - * @return model - */ - public function getModel ($name) - { - require_once 'core/mapper/mapper.php'; // ???? - - require_once (Shortcut::getUrl(self::$shortcut, $name)); - $modelName = $name . "Mapper"; - $model = new $modelName(); - $model->db = $this->db; - $model->factory = $this; - return $model; - } -} diff --git a/core/mapper/mapper.php b/core/mapper/mapper.php deleted file mode 100644 index 07d30ba..0000000 --- a/core/mapper/mapper.php +++ /dev/null @@ -1,267 +0,0 @@ - DataMapper implements IDataList, IDataSave, IDataSort, IDataDelete ... - * - * @package core - */ -class DataMapper implements IDataList -{ - /* Хранить метаданные в статическом свойстве класса для ототбражения ?!, + Скрипт для генерации метаданных!! - */ - public $factory; - public $className; /* Класс на который будет отображаться строчка таблицы */ - public $filter = ""; /* */ - public $schema = array (); /* Соответствие между свойством обьекта и столбцом, добавить тип для записей !! */ - public $database; /* Таблица */ - public $index; /* Индексный столбец */ - public $db; /* Соединение с базой данных */ - public $reference = array (null, null); - - public function __construct () - { - } - - public function setRange ($stmt, $page, $size) - { - $stmt->setLimit ($size); - $stmt->setOffset (($page-1) * $size); - } - - public function listSQL (array $list) - { - return implode ($list, ","); - } - - /** - * Поиск строки в таблице по идентификатору - * @param $id Значение идентификатора - * @return Обьект класса $className - */ - public function findById ($id) - { - // Строки запроса преобразовать в методы (getSQLSelect ...) - // Query::from($this->database)->where ($this->index, "=", $id)->select(); - $stmt = $this->db->prepareStatement ("SELECT * FROM ".$this->database." WHERE ".$this->index." = ?"); - $stmt->setInt (1, $id); - $rs = $stmt->executeQuery (); - $rs->next (); - return $this->mapOne ($rs); - } - - /** - * Преобразует parseResult в обьект - */ - public /* private */ function mapOne ($rs) - { - $result = new $this->className (); - foreach ($this->schema as $key => $value) { - list($value) = $value; - $result->$value->setRes($rs, $key); - } - return $result; - } - - public /* private */ function mapAll ($rs) - { - $result = array (); - // Преобразование SQL в обьект - while ($rs->next ()) { - $result[] = $this->mapOne ($rs); - } - return $result; - } - - private function clean ($value) { - return strtolower(trim(iconv('utf-8', 'cp1251', $value))); - } - - /** - * Преобразует параметры формы в SQL запрос WHERE - * @param array $params - * @param array $schema - * @return string - */ - public function requestToSQL (Collection $request, array $schema) - { - $result = array (); - foreach ($schema as $key => $value) { - $param = $request->get ($key); - if ($param) { - array_push ($result, "lower (".$value.") LIKE '".$this->clean ($param)."%'"); - } - } - if (empty ($result)) return null; - return implode ($result, " AND "); - } - - /** - * Удаление строк из таблицы с заданными индексами - * @param $list array Массив идентефикаторов - */ - public function deleteList (array $list) - { - // Query::from($this->database)->where($this->index, "in", $list)->delete(); - $sql = "DELETE FROM " . $this->database . " WHERE " . $this->index . " IN (" . $this->listSQL ($list) . ")"; - return $this->db->executeQuery ($sql); - } - - public static function findKey (array $schema, $sort) - { - foreach ($schema as $key => $item) { - list($item) = $item; - if ($item == $sort) { - return $key; - } - } - return $sort; - } - - public function getOrder (Collection $request) - { - $order = ""; - $sort = $request->get('key'); - $desc = ($request->get('desc') == 0)? 'DESC' : 'ASC'; - if ($sort) { - $sort = self::findKey ($this->schema, $sort); - $order = " ORDER BY $sort $desc"; - } - return $order; - } - - /** - * Извлекает список записей из базы данных - */ - public function findAll (Collection $request, $id = null) - { - $name0 = $this->database; - $foreign = $this->reference[1]; - // Переписать используя Query !!! - if ($foreign && $id) { - $filter = ($this->filter)?$filter = " AND ".$this->filter: ""; - $sql = "SELECT t1.* FROM $name0 as t1 WHERE t1.$foreign = $id " . $filter.self::getOrder($request); - } else { - $filter = ($this->filter)?$filter = " WHERE " . $this->filter: ""; - $sql = "SELECT * FROM $name0 " . $filter . self::getOrder($request); - } - $stmt = $this->db->prepareStatement ($sql); - - $page = $request->get('page'); - $limit = $request->get('size'); - if ($page && $limit) { - $this->setRange($stmt, $page, $limit); - } - - return $this->mapAll($stmt->executeQuery()); - } - - public function getCount (Collection $request, $id) - { - $name0 = $this->database; - $foreign = $this->reference[1]; - // Переписать используя Query !!! - if ($foreign && $id) { - $filter = ($this->filter)?$filter = " AND " . $this->filter: ""; - $sql = "SELECT count(t1.*) as length FROM $name0 as t1 WHERE t1.$foreign = $id " . $filter; - } else { - $filter = ($this->filter)?$filter = " WHERE " . $this->filter: ""; - $sql = "SELECT count(*) as length FROM $name0 " . $filter; - } - $rs = $this->db->executeQuery($sql); - $rs->next(); - return $rs->getInt('length'); - } - - /** - * Добавление записи в базу данных - * @param $o Обьект для записи в базу данных - */ - public function saveTo (Model $o) - { - $keys = array (); - $values = array (); - foreach ($this->schema as $key => $value) { - list($value) = $value; - if ($key != $this->index) { - $keys[] = $key; - $values[] = "'".$o->$value."'"; - } - } - $stmt = $this->db->prepareStatement ("INSERT INTO ".$this->database." (".implode ($keys, ",").") VALUES (".implode ($values, ",").")"); - $stmt->executeQuery (); - } - - /** - * Обновляет запись в базе данных - * @param $o Обьект для обновления - */ - public function updateTo (Model $o) - { - $keys_values = array (); - foreach ($this->schema as $key => $value) { - list($value) = $value; - if ($key != $this->index && !($o->$value instanceof FKey)) { - $keys_values[] = $key." = '".$o->$value."'"; - } - } - // Для всех должен быть идентефикатор id - $stmt = $this->db->prepareStatement ("UPDATE ".$this->database." SET ".implode($keys_values, ",")." WHERE ".$this->index." = ".$o->id); - $stmt->executeQuery (); - } - - function saveDB (Model $o) - { - if ($o->id) { - $this->updateTo($o); - } else { - $this->saveTo($o); - } - } - - function getModel($name) - { - require_once 'core/Mapper/Factory.php'; - if (!$this->factory) { - $this->factory = new ModelFactory($this->db); - } - return $this->factory->getModel($name); - } -} - -/** - * - */ -class Model -{ - public function __construct () - { - foreach (get_class_vars (get_class ($this)) as $key => $value) { - $this->$key = new Primitive (); - } - } - // __get, __set методы. В метаданных хранится тип свойств, проверять при присваивании!! -} - -?> \ No newline at end of file diff --git a/core/mapper/pathmapper.php b/core/mapper/pathmapper.php deleted file mode 100644 index 32d0a1f..0000000 --- a/core/mapper/pathmapper.php +++ /dev/null @@ -1,78 +0,0 @@ - $value) { - $target->$name = $array->get($name); - } - } - - function basePath () - { - if ( ! $this->base) $this->base = $this->getBasePath(); - return $this->base; - } - - function findAll (Collection $request, $id = null) - { - require_once "core/settings.php"; - require_once "core/path.php"; - - $this->reference = $id; - - $base = $this->basePath (); - $path = new Path($base); - $list = $path->getContent(); - - $result = array (); - $this->count = 0; - foreach ($list as $name) { - if (is_dir (Path::join($this->basePath (), $name)) - && $module = $this->findById ($name)) { - $this->count++; - $result [] = $module; - } - } - return $result; - } - - function findById ($name) - { - $file = Path::join($this->basePath(), $this->getSettingsFile ($name)); - if (file_exists($file)) { - $settings = new Settings($file); - $settings->read(); - return $this->settingsMap($name, $settings); - } - return null; - } - - /** - * Число папок - */ - function getCount () - { - return $this->count; - } - - /** - * Удаление списка папок - */ - function deleteList(array $list) - { - foreach ($list as $name) - Path::delete(Path::join($this->getBasePath(), $name)); - } -} - -?> \ No newline at end of file diff --git a/core/markup/simple_bb_code.php b/core/markup/simple_bb_code.php deleted file mode 100644 index 3bb16f3..0000000 --- a/core/markup/simple_bb_code.php +++ /dev/null @@ -1,113 +0,0 @@ - 'strong','i' => 'em','u' => 'span style="text-decoration:underline"','quote' => 'blockquote','s' => 'span style="text-decoration: line-through"', 'list' => 'ul','\*' => 'li'); - //Tags that must be mapped to diffierent parts - var $mapped = array('url' => array('a','href',true),'img' => array('img','src',false)); - //Tags with atributes - var $tags_with_att = array('color' => array('font','color'),'size' => array('font','size'),'url' => array('a','href')); - //Gotta have smilies - var $smilies = array(':)' => 'smile.gif',':(' => 'frown.gif'); - //Config Variables - //Convert new line charactes to linebreaks? - var $convert_newlines = true; - //Parse For smilies? - var $parse_smilies = true; - //auto link urls(http and ftp), and email addresses? - var $auto_links = true; - //Internal Storage - var $_code = ''; - function Simple_BB_Code($new=true,$parse=true,$links=true){ - $this->convert_newlines = $new; - $this->parse_smilies = $parse; - $this->auto_links = $links; - } - function parse($code){ - $this->_code = $code; - $this->_strip_html(); - $this->_parse_tags(); - $this->_parse_mapped(); - $this->_parse_tags_with_att(); - $this->_parse_smilies(); - $this->_parse_links(); - $this->_convert_nl(); - return $this->_code; - } - function _strip_html(){ - $this->_code = strip_tags($this->_code); - } - function _convert_nl(){ - if($this->convert_newlines){ - $this->_code = nl2br($this->_code); - } - } - function _parse_tags(){ - foreach($this->tags as $old=>$new){ - $ex = explode(' ',$new); - $this->_code = preg_replace('/\['.$old.'\](.+?)\[\/'.$old.'\]/is','<'.$new.'>$1',$this->_code); - } - } - function _parse_mapped(){ - foreach($this->mapped as $tag=>$data){ - $reg = '/\['.$tag.'\](.+?)\[\/'.$tag.'\]/is'; - if($data[2]){ - $this->_code = preg_replace($reg,'<'.$data[0].' '.$data[1].'="$1">$1',$this->_code); - } - else{ - $this->_code = preg_replace($reg,'<'.$data[0].' '.$data[1].'="$1">',$this->_code); - } - } - } - function _parse_tags_with_att(){ - foreach($this->tags_with_att as $tag=>$data){ - $this->_code = preg_replace('/\['.$tag.'=(.+?)\](.+?)\[\/'.$tag.'\]/is','<'.$data[0].' '.$data[1].'="$1">$2',$this->_code); - } - } - function _parse_smilies(){ - if($this->parse_smilies){ - foreach($this->smilies as $s=>$im){ - $this->_code = str_replace($s,'',$this->_code); - } - } - } - function _parse_links(){ - if($this->auto_links){ - $this->_code = preg_replace('/([^"])(http:\/\/|ftp:\/\/)([^\s,]*)/i','$1$2$3',$this->_code); - $this->_code = preg_replace('/([^"])([A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4})/i','$1$2',$this->_code); - } - } - function addTag($old,$new){ - $this->tags[$old] = $new; - } - function addMapped($bb,$html,$att,$end=true){ - $this->mapped[$bb] = array($html,$att,$end); - } - function addTagWithAttribute($bb,$html,$att){ - $this->tags_with_att[$bb] = array($html,$att); - } - function addSmiley($code,$src){ - $this->smilies[$code] = $src; - } -} -?> \ No newline at end of file diff --git a/core/path.php b/core/path.php deleted file mode 100644 index 70e83c0..0000000 --- a/core/path.php +++ /dev/null @@ -1,317 +0,0 @@ -path = $this->fromString($path); - $this->optimize(); - } - - static function factory($path) { - return new Path($path); - } - - /** - * Возвращает расширение файла - * - * @param string $fileName Полное имя файла - * - * @return string - */ - static function getExtension ($fileName) - { - assert(is_string($fileName)); - - return pathinfo($fileName, PATHINFO_EXTENSION); - } - - /** - * Полное имя файла без расширения - * - * @param string $fileName Имя файла - * - * @return string - */ - static function skipExtension ($fileName) - { - assert(is_string($fileName)); - - $path = pathinfo($fileName); - if ($path['dirname'] == ".") { - return $path['filename']; - } else { - return self::join($path['dirname'], $path['filename']); - } - } - - /** - * Возвращает имя файла без расширения - * - * @param string $fileName Полное имя файла - * - * @return string - */ - static function getFileName ($fileName) - { - assert(is_string($fileName)); - - return pathinfo($fileName, PATHINFO_FILENAME); - } - - /** - * Список файлов в директории - * - * @param array $allow массив расширений для файлов - * @param array $ignore массив имен пааок которые не нужно обрабатывать - * - * @return array - */ - public function getContent ($allow = null, $ignore = array()) - { - $ignore = array_merge(array (".", "..", $ignore)); - return self::fileList($this->__toString(), $allow, $ignore); - } - - // Использовать SPL ??? - protected function fileList ($base, &$allow, &$ignore) - { - $result = array (); - if ($handle = opendir($base)) { - while (false !== ($file = readdir($handle))) { - if (! in_array ($file, $ignore)) { - $isDir = is_dir (Path::join ($base, $file)); - if ($isDir || ($allow == null) || in_array (self::getExtension($file), $allow)) { - $result[] = $file; - } - } - } - closedir($handle); - } - return $result; - } - - protected function fileListAll (&$result, $base, &$allow, &$ignore) - { - $files = self::fileList($base, $allow, $ignore); - foreach ($files as $name) { - $fullname = self::join($base, $name); - if (is_dir($fullname)) { - self::fileListAll($result, $fullname, $allow, $ignore); - } else { - array_push ($result, $fullname); - } - } - } - - /** - * Список файлов в директориии и ее поддиректорий - * - * @param array $allow массив расширений разрешеных для файлов - * @param array $ignore массив имен пааок которые не нужно обрабатывать - * - * @return array - */ - function getContentRec ($allow = null, $ignore = array()) - { - $result = array (); - $ignore = array_merge(array (".", ".."), $ignore); - self::fileListAll($result, $this->__toString(), $allow, $ignore); - return $result; - } - - - /** - * Рекурсивно копирует директорию - * - * @param string $source Папка из которой копируется - * @param string $target Папка в которую копируется - */ - public static function copy ($source, $target) - { - if (is_dir($source)) { - if (! file_exists($target)) mkdir ($target); - $path = new Path($source); - $files = $path->getContent(); - foreach ($files as $file) { - $entry = self::join($source, $file); - if (is_dir($entry)) { - self::copy($entry, Path::join($target, $file)); - } else { - copy($entry, Path::join($target, $file)); - } - } - } - } - - /** - * Рекурсивно удаляет директорию - * - * @param string $path Папка - */ - public static function delete ($path) - { - assert(is_string($path)); - - if (is_dir($path)) { - foreach(glob($path . '/*') as $sf) { - if (is_dir($sf) && !is_link($sf)) { - self::delete($sf); - } else { - unlink($sf); - } - } - rmdir($path); - } - } - - /** - * Преобразует строку путя в массив - * - * @param string $path Путь - * - * @return array - */ - public function fromString ($path) - { - assert(is_string($path)); - - $list = preg_split("/[\/\\\\]/", $path); - return $list; - } - - /** - * Преобразует относительный путь в абсолютный - */ - public function optimize () - { - $result = array(current($this->path)); - while (next($this->path) !== false) { - $n = current ($this->path); - switch ($n) { - case "": break; - case ".": break; - case "..": if (count($result) > 0) array_pop($result); break; - default: - array_push($result, $n); - } - } - reset($this->path); - $this->path = $result; - } - - /** - * Преобразует путь в строку - * - * @return string - */ - public function __toString () - { - $result = implode($this->path, self::SEPARATOR); - return $result; - } - - /** - * Проверяет является ли папка родительской для другой папки - * - * @parma Path $path - * - * @return boolean - */ - public function isParent ($path) - { - if (count($path->path) > count($this->path)) { - for ($i = 0; $i < count($this->path); $i++) { - if ($path->path[$i] != $this->path[$i]) { - return false; - } - } - return true; - } - return false; - } - - /** - * Находит путь относительно текущего путя - * - * @param string $name Полный путь к файлу - * - * @return string Относительный путь к файлу - */ - public function relPath ($name) - { - $path = new Path ($name); - foreach ($this->path as $n) { - array_shift($path->path); - } - return $path->__toString(); - } - - public function append ($path) - { - $base = $this->__toString(); - return self::join($base, $path); - } - - /** - * Создает недастающие папки для записи файла - * - * @param string $dst Полное имя файла - * - * @return void - */ - static function prepare ($dst) - { - $path_dst = pathinfo($dst, PATHINFO_DIRNAME); - if (! file_exists($path_dst)) { - mkdir($path_dst, 0700, true); - } - } - - /** - * Подбирает новое временное имя для файла - * - * @param string $dst Предпологаемое имя файла - * - * @return string Новое имя файла - */ - static function resolveFile ($dst) - { - $i = 0; - $file = self::skipExtension($dst); - $suffix = self::getExtension($dst); - $temp = $dst; - while (file_exists($temp)) { - $i ++; - $temp = $file . "." . $i . "." . $suffix; - } - return $temp; - } - - /** - * Обьединяет строки в путь соединяя необходимым разделителем - * - * @return string - */ - static function join () - { - $args = func_get_args(); - return implode(self::SEPARATOR, $args); - } -} diff --git a/core/primitive.php b/core/primitive.php deleted file mode 100644 index ff10b89..0000000 --- a/core/primitive.php +++ /dev/null @@ -1,105 +0,0 @@ -name = $name; - } - - // Преобразование из внешнего вормата - public function setString ($value) - { - $this->value = $value; - } - - // Преобразование из формата базы данных - public function setRes ($res, $key) - { - $this->value = $res->getString ($key); - } - - public function __toString () - { - return ((string) $this->value); - } - - // Преобразование во внешний формат - public function getString () - { - return $this->__toString (); - } -} - -/** - * Отображение поля таблицы в целое число - * @package core - */ -class Int4 extends Primitive { - public function setRes ($res, $key) { - $this->value = $res->getInt ($key); - } - - public function setString ($value) { - $this->value = ((int) $value); - } -} - -/* Foreign key */ -class FKey extends Int4 {} - -/** - * Отображение поля таблицы в дату - время - */ -class Date extends Primitive -{ - public function setRes ($res, $key) - { - $this->value = $res->getInt ($key); - } - - public function setString ($value) - { - $this->value = 0; - if ($tmp = explode("/",$value,3)) { - if ($tmp[1] && $tmp[0] && $tmp[2]) { - if (checkdate($tmp[1], $tmp[0], $tmp[2])) { - $this->value = mktime(0, 0, 0, $tmp[1], $tmp[0], $tmp[2]); - } - } - } - } - - public function getString () - { - return date ("d/m/Y", $this->value); - } -} - -/** - * - */ -class Password extends Primitive -{ - public function setRes ($res, $key) - { - $this->value = $res->getString($key); - } - - public function setString ($value) - { - $this->value = md5($value); - } - - public function getString () - { - return $this->value; - } -} - -?> \ No newline at end of file diff --git a/core/query/meta.php b/core/query/meta.php deleted file mode 100644 index c1320a7..0000000 --- a/core/query/meta.php +++ /dev/null @@ -1,9 +0,0 @@ -type = 'simple'; - $table->name = $name; - $table->alias = "t" . self::$alias++; - - $result->table = $table; - - return $result; - } - - /** - * Добавляет к запросу условие - * @param string $field Имя поля таблицы - * @param string $op Имя оператора - * @param $value Значение поля - * - * @return Query - */ - public function filter($field, $op, $value) - { - $result = clone $this; - $result->filter [] = $result->table->alias ."." . $field . $op . "'" . $value . "'"; - return $result; - } - - /** - * @param string $e Выражение - */ - public function calc($e) - { - $result = clone $this; - $result->calc [] = $e; - return $result; - } - - public function joinOn($first, $e) - { - $result = $this->compose($first, array ('filter', 'calc', 'order')); - - $e = strtr($e, array ("a." => $this->table->alias . ".", - "b." => $first->table->alias . ".")); - - $table = new Table (); - $table->type = 'join'; - $table->name = $this->table->name; - $table->alias = $this->table->alias; - $table->join = $first->table; - $table->condition = $e; - - $result->table = $table; - - return $result; - } - - /** - * Обьединяет параметры двух заросов - * @param Query $first - * @pram array $list Список параметров - * - * @return Query - */ - private function compose(Query $first, array $list) - { - $result = new Query(); - foreach ($list as $name) { - $result->$name = array_merge($this->$name, $first->$name); - } - return $result; - } - - /** - * Заковычивает значение - */ - public function quote ($value) - { - return "'" . $value . "'"; - } - - /** - * Компиляция таблицы - * @param Table $table - * - * @return string Часть строки SQL - */ - private function table(Table $table) - { - if ($table->type == 'simple') { - return $table->name ." AS ".$table->alias; - } - if ($table->type == 'join') { - return $table->name ." AS ".$table->alias. " JOIN " . $this->table ($table->join) . " ON " . $table->condition; - } - return ""; - } - - /** - * Компиляция WHERE - * - * @return string Часть строки SQL - */ - private function where () - { - return implode(" AND ", $this->filter); - } - - /** - * Компиляция запроса в SELECT SQL - * - * @return string SQL выражение - */ - public function select() - { - return "SELECT " - . ((!empty($this->calc))? implode (",", $this->calc): "*") - . " FROM " . $this->table($this->table) - . ((!empty ($this->filter))? " WHERE " . $this->where() : ""); - } - - /** - * Компиляция в DELETE - */ - public function delete() - { - return "DELETE FROM " . $this->table->name - . ((!empty ($this->filter))? " WHERE " . $this->where() : ""); - } - - private function add_prefix($prefix, $array) { - $result = array(); - foreach ($array as $value) { - $result [] = $prefix . $value; - } - return $result; - } - - /** - * Компиляция в UPDATE - * TODO: Разные типы запросов Query->update(); Query->select(), Query->insert();!! - * Возвраащают statement - */ - public function update($values) - { - $pairs = array (); - foreach ($values as $key => $value) { // - $pairs [] = $key . "=" . $this->quote ($value); - } - return "UPDATE " . $this->table->name . " SET " - . implode(",", $pairs) - . ((!empty($this->filter))? " WHERE " . $this->where() : ""); - } - - /** - * Компиляция в INSERT - */ - public function insert($values) - { - return "INSERT INTO ". $this->table->name . "(" - . implode(",", array_keys($values)) - . ") VALUES (" . implode(",", array_map(array($this, 'quote'), array_values($values))) . ")"; - } -} - diff --git a/core/query/table.php b/core/query/table.php deleted file mode 100644 index 19f67a4..0000000 --- a/core/query/table.php +++ /dev/null @@ -1,14 +0,0 @@ -data = $this->_stripSlashes($this->data); - } - $this->data = $this->data; - } - - function import(array $data) - { - parent::import($data); - $this->_clean(); - } - - /** - * Strip slashes code from php.net website. - * - * @param mixed $value - * @return array - */ - protected function _stripSlashes($value) - { - if(is_array($value)) { - return array_map(array($this,'_stripSlashes'), $value); - } else { - return stripslashes($value); - } - } -} diff --git a/core/setup.php b/core/setup.php deleted file mode 100644 index cba50ef..0000000 --- a/core/setup.php +++ /dev/null @@ -1,59 +0,0 @@ -getContentRec(null, array(".svn")); - - foreach ($files as $file) { - if (Path::getExtension($file) == $tplFile) { - // Шаблон - $dst = $out->append($path->relPath (Path::skipExtension($file))); - Path::prepare($dst); - file_put_contents($dst, self::fileContent($file, $tpl)); - } else { - // Обычный файл - $dst = $out->append($path->relPath ($file)); - Path::prepare($dst); - copy($file, $dst); - } - } - } - - /** - * Выполнение Списка SQL команд - */ - static function batchSQL(Connection $conn, $file) - { - $stmtList = SQLStatementExtractor::extractFile ($file); - foreach ($stmtList as $stmt) { - $conn->executeQuery ($stmt); - } - } -} - -?> \ No newline at end of file diff --git a/core/spell.php b/core/spell.php deleted file mode 100644 index bc45a0d..0000000 --- a/core/spell.php +++ /dev/null @@ -1,100 +0,0 @@ - SpellHelper ?? - */ -class Spell -{ - private $pspell; - public $autocorrect = false; - public function __construct ($language, $encoding) - { - $this->pspell = pspell_new($language, '', '', $encoding, PSPELL_NORMAL); - } - - function spellCheckWord ($word) - { - $word = $word[0]; - - // Ignore ALL CAPS - if (preg_match('/^[A-Z0-9]*$/', $word)) return $word; - - // Return dictionary words - if (pspell_check($this->pspell, $word)) - return $word; - - // Auto-correct with the first suggestion, color green - if ($this->autocorrect && $suggestions = pspell_suggest($this->pspell, $word)) - return '' . current($suggestions) . ''; - - // No suggestions, color red - return '' . $word . ''; - } - - function isGoodWord ($word) - { - // Ignore ALL CAPS - if (preg_match('/^[A-Z]*$/', $word)) return true; - if (preg_match('/^[0-9]*$/', $word)) return true; - - // Return dictionary words - if (pspell_check($this->pspell, $word)) - return true; - - return false; - } - - function suggest ($string) - { - return preg_replace_callback('/\b\w+\b/', array($this, 'spellCheckWord'), $string); - } - - /** - * Вызывает функцию для каждого найденного слова - */ - function eachWord ($call, $string) - { - $begin = indexLeft ($string, 'ctype_alpha', 0); - while ($begin !== false) { - $end = indexLeft ($string, 'not_ctype_alpha', $begin); - call_user_func ($call, $string, $begin, $end); - $begin = indexLeft ($string, 'ctype_alpha', $end); - } - return false; - } - - /** - * Проверяет слово на соответствие со словарем - * - */ - function doWord (&$string, $begin, $end) - { - $word = substr($string, $begin, $end - $begin); - if (! $this->isGoodWord ($word)) { - $start = max(indexLeft ($string, 'not_ctype_alpha', $begin - 100), 0); - $offset = indexLeft ($string, 'not_ctype_alpha', $end + 100); - if (! $offset) { - $offset = strlen($string); - } - $length = $offset - $start; - throw new Exception ($this->suggest(substr($string, $start, $length))); - } - } - - /** - * Часть текста содержащий неправильное слово - */ - function getError ($string) - { - try { - self::eachWord (array ($this, 'doWord'), $string); - } catch (Exception $e) { - return $e->getMessage(); - } - return false; - } -} - -?> \ No newline at end of file diff --git a/core/tabletree.php b/core/tabletree.php deleted file mode 100644 index 4f63c71..0000000 --- a/core/tabletree.php +++ /dev/null @@ -1,69 +0,0 @@ - 1), array ('name' => 2), array ('name' => 1))) - => array (1, 2) - * @end example - */ -function key_unique_values ($name, $table) { - // Ищем уникальные значения для заданного ключа - $keys = array (); - foreach ($table as $row) { - if (!in_array ($row[$name], $keys)) - $keys[] = $row[$name]; - } - return $keys; -} - -/** - * Сортировка двумерного массива по заданному ключу - * @param $array Массив - * @param $key Имя ключа по значению которого будет идти сравнение - * @return Отсортированный массив - */ -function sortOn($array, $key, $fn = '__cmp') { - usort ($array, rcurry($fn, $key)); - //usort ($array, create_function ('$x,$y', 'return __cmp ($x, $y, "'.$key.'");')); - return $array; -} - - -/** - * Обходит таблицу как дерево - * @param $level Array Уровни вложенности - * @param $table Таблица - * @param $fn Функция которая применяется к каждой ветке дерева - * $fn ($name, $index, $rows, $cc) - * @param $name Ключ уровня - * @param $index Значение ключа уровня - * @param $rows Все столбцы текущго уровня - * @parma $cc Столбцы более низкого уровня - */ -function tableTreeWalk($level, $table, $fn) { - if (empty ($level)) return $table; - $name = array_shift ($level); - - $keys = key_unique_values($name, $table); - $data = array (); - foreach ($keys as $index) { - list($rows, $table) = partition (lcurry('__index', $index, $name), $table); -// $rows = array_filter ($table, lcurry('__index', intval($index), $name)); - //$rows = array_filter ($table, create_function ('$x', 'return __index ('.intval($index).', \''.$name.'\', $x);')); - $data[$index] = call_user_func ($fn, $name, $index, $rows, tableTreeWalk ($level, $rows, $fn)); - } - return $data; -} - diff --git a/core/tales.php b/core/tales.php deleted file mode 100644 index e474ad6..0000000 --- a/core/tales.php +++ /dev/null @@ -1,34 +0,0 @@ -registerPrefix('date', array('DateTime_Tales', 'date')); -$registry->registerPrefix('time', array('DateTime_Tales', 'time')); - - -function phptal_date ($e) -{ - return date ("d.m.Y", $e); -} - -function phptal_time ($e) -{ - return date ("H:i", $e); -} diff --git a/core/tools/password.php b/core/tools/password.php deleted file mode 100644 index 1308a52..0000000 --- a/core/tools/password.php +++ /dev/null @@ -1,32 +0,0 @@ - 0) { // already in sub-array? - $subarr[$in_subarr][] = $tok; - if ('}' === substr($tok, -1, 1)) { // check to see if we just added last component - $res[] = $this->strToArray(implode(',', $subarr[$in_subarr])); - $in_subarr--; - } - } elseif ($tok{0} === '{') { // we're inside a new sub-array - if ('}' !== substr($tok, -1, 1)) { - $in_subarr++; - // if sub-array has more than one element - $subarr[$in_subarr] = array(); - $subarr[$in_subarr][] = $tok; - } else { - $res[] = $this->strToArray($tok); - } - } else { // not sub-array - $val = trim($tok, '"'); // remove " (surrounding strings) - // perform type castng here? - $res[] = $val; - } - } - - return $res; -} diff --git a/core/tools/tableview.php b/core/tools/tableview.php deleted file mode 100644 index 55dea4b..0000000 --- a/core/tools/tableview.php +++ /dev/null @@ -1,94 +0,0 @@ -list = $list; - } - - function makeTable() { - $xls = new ExcelTable(); - $xls->setRow(1, 1, array_keys($this->list)); - - foreach($this->data as $n => $item) { - $result = array(); - foreach($this->list as $key => $c) { - if (is_callable($c)) { - $result [] = call_user_func($c, $item, $n); - } else { - if (is_numeric($item[$c])) { - $result [] = new Excel_Number($item[$c]); - } else { - $result [] = $item[$c]; - } - } - } - $xls->addRow(1, $result); - } - - return $xls; - } - - function writeTable($data, $file) { - $this->data = $data; - - $xls = new ExcelDocument(); - $xls->addTable(array($this, 'makeTable')); - $xls->save($file); - } -} - -class TableHTMLView { - private $list = array(); - private $stack = array(); - private $result = array(); - - function writeElement($name, $content) { - echo "<".$name.">"; - echo $content; - echo ""; - } - - function startElement($name) { - array_push($this->stack, $name); - echo "<".$name.">"; - } - - function endElement() { - $name = array_pop($this->stack); - echo ""; - } - - function setColumns(array $list) { - $this->list = $list; - } - - function writeTable($data) { - $this->startElement('table'); - $this->startElement('thead'); - $this->startElement('tr'); - foreach($this->list as $key => $c) { - $this->writeElement('th', $key); - } - $this->endElement(); - $this->endElement(); - - $this->startElement('tbody'); - foreach($data as $n => $item) { - $this->startElement('tr'); - foreach($this->list as $key => $c) { - if (is_callable($c)) { - $this->writeElement('td', call_user_func($c, $item, $n)); - } else { - $this->writeElement('td', $item[$c]); - } - } - $this->endElement(); - } - $this->endElement(); - $this->endElement(); - } -} - diff --git a/core/tools/translit.php b/core/tools/translit.php deleted file mode 100644 index 1ca001c..0000000 --- a/core/tools/translit.php +++ /dev/null @@ -1,14 +0,0 @@ -"zh", "ц"=>"ts", "ч"=>"ch", "ш"=>"sh", - "щ"=>"shch","ь"=>"", "ю"=>"yu", "я"=>"ya", - "Ж"=>"ZH", "Ц"=>"TS", "Ч"=>"CH", "Ш"=>"SH", - "Щ"=>"SHCH","Ь"=>"", "Ю"=>"YU", "Я"=>"YA", - "ї"=>"i", "Ї"=>"Yi", "є"=>"ie", "Є"=>"Ye" - )); - return $st; -} diff --git a/core/tree/database.php b/core/tree/database.php deleted file mode 100644 index c9c8133..0000000 --- a/core/tree/database.php +++ /dev/null @@ -1,135 +0,0 @@ - -// Category: Databases -//**************************************************************************** -// The lib is FREEWARE. This means you may use it anywhere you want, you may -// do anything with it. The Author mentioned above is NOT responsible for any -// consequences of using this library. -// If you don't agree with this, you MAY NOT use the lib! -//**************************************************************************** -// All improvings, feature requests, bug reports, etc. are gladly accepted. -//**************************************************************************** -// Note: For best viewing of the code Tab size 4 is recommended -//**************************************************************************** - -class CDatabase -{ - var $link; - var $db; - var $host, $user, $pass; - - function CDatabase($db, $host = "localhost", $user = "", $pass = "") - { - $this->db = $db; - $this->host = $host; - $this->user = $user; - $this->pass = $pass; - $str = "host={$host} port=5432 dbname={$db} user={$user} password={$pass}"; - $this->link = pg_connect($str); - } - - function query($sql) - { - if (!$this->link) return 0; - return pg_query($this->link, $sql); - } - - function affected_rows() - { - return pg_affected_rows($this->link); - } - - function num_rows($q) - { - return pg_num_rows($q); - } - - function fetch_array($q) // fetchAll - { - return pg_fetch_array($q, NULL); - } - - function fetch_object($q) // fetchObject - { - return pg_fetch_object($q); - } - /* function data_seek($q, $n) { - return pg_data_seek($q, $n); - } - */ - - function free_result($q) - { - return pg_free_result($q); - } - - function insert_id($seq) - { - $query = "SELECT currval('$seq')"; - $res = $this->query($query); - $row = pg_fetch_array($res, NULL, PGSQL_ASSOC); - pg_free_result($res); - return ($row) ? $row['currval'] : 0; - } - - function error() - { - return pg_last_error($this->link); - } - - function error_die($msg = '') - { - die(((empty($msg)) ? '' : $msg . ': ') . $this->error()); - } - - function sql2var($sql) - { - - if ((empty($sql)) || (!($query = $this->query($sql)))) return false; - - if ($this->num_rows($query) < 1) return false; - return $this->result2var($query); - } - - function result2var($q) - { - - if (!($Data = $this->fetch_array($q))) return false; - $this->free_result($q); - - foreach($Data as $k => $v) $GLOBALS[$k] = $v; - return true; - } - - /*function sql2array($sql, $keyField = '') - { - - if ((empty($sql)) || (!($query = $this->query($sql)))) return false; - - if ($this->num_rows($query) < 1) return false; - return $this->result2array($query, $keyField); - }*/ - - function result2array($q, $keyField = '') - { - $Result = array(); - while ($Data = $this->fetch_array($q)) - if (empty($keyField)) $Result[] = $Data; - else $Result[$Data[$keyField]] = $Data; - $this->free_result($q); - return $Result; - } - - /*function list_tables() - { - return mysql_list_tables($this->db, $this->link); - } - - function list_fields($table_name) - { - return mysql_list_fields($this->db, $table_name, $this->link); - }*/ -}; diff --git a/core/tree/dbtree.php b/core/tree/dbtree.php deleted file mode 100644 index ad83ab3..0000000 --- a/core/tree/dbtree.php +++ /dev/null @@ -1,636 +0,0 @@ - -// WWW: http://dev.e-taller.net/dbtree/ -// Category: Databases -// Description: PHP class implementing a Nested Sets approach to storing -// tree-like structures in database tables. This technique was -// introduced by Joe Celko and has some -// advantages over a widely used method called Adjacency Matrix. -//**************************************************************************** -// The lib is FREEWARE. That means you may use it anywhere you want, you may -// do anything with it. The Author mentioned above is NOT responsible for any -// consequences of using this library. -// If you don't agree with this, you are NOT ALLOWED to use the lib! -//**************************************************************************** -// You're welcome to send me all improvings, feature requests, bug reports... -//**************************************************************************** -// SAMPLE DB TABLE STRUCTURE: -// -// CREATE TABLE categories ( -// cat_id INT UNSIGNED NOT NULL AUTO_INCREMENT, -// cat_left INT UNSIGNED NOT NULL, -// cat_right INT UNSIGNED NOT NULL, -// cat_level INT UNSIGNED NOT NULL, -// PRIMARY KEY(cat_id), -// KEY(cat_left, cat_right, cat_level) -// ); -// -// This is believed to be the optimal Nested Sets use case. Use `one-to-one` -// relations on `cat_id` field between this `structure` table and -// another `data` table in your database. -// -// Don't forget to make a single call to clear() -// to set up the Root node in an empty table. -// -//**************************************************************************** -// NOTE: Although you may use this library to retrieve data from the table, -// it is recommended to write your own queries for doing that. -// The main purpose of the library is to provide a simpler way to -// create, update and delete records. Not to SELECT them. -//**************************************************************************** -// -// IMPORTANT! DO NOT create either UNIQUE or PRIMARY keys on the set of -// fields (`cat_left`, `cat_right` and `cat_level`)! -// Unique keys will destroy the Nested Sets structure! -// -//**************************************************************************** -// CHANGELOG: -// 16-Apr-2003 -=- 1.1 -// - Added moveAll() method -// - Added fourth parameter to the constructor -// - Renamed getElementInfo() to getNodeInfo() /keeping BC/ -// - Added "Sample Table Structure" comment -// - Now it trigger_error()'s in case of any serious error, because if not you -// will lose the Nested Sets structure in your table -// 19-Feb-2004 -=- 1.2 -// - Fixed a bug in moveAll() method? -// Thanks to Maxim Matyukhin for the patch. -// 13-Jul-2004 -=- 1.3 -// - Changed all die()'s for a more standard trigger_error() -// Thanks to Dmitry Romakhin for pointing out an issue with -// incorrect error message call. -// 09-Nov-2004 -=- 1.4 -// - Added insertNear() method. -// Thanks to Michael Krenz who sent its implementation. -// - Removed IGNORE keyword from UPDATE clauses in insert() methods. -// It was dumb to have it there all the time. Sorry. Anyway, you had -// to follow the important note mencioned above. If you hadn't, you're -// in problem. -// -//**************************************************************************** -// Note: For best viewing of the code Tab size 4 is recommended -//**************************************************************************** - -function _case($c, $then, $else) { - return " (CASE WHEN $c THEN $then ELSE $else END) "; -} - -function _between($a, $x, $y) { - return " " . $a . " BETWEEN " . $x . " AND " . $y; -} - -function _inside($a, $x, $y) { - return " " . $a . " > " . $x . " AND " . $a . " < " . $y; -} - -class CDBTree -{ - var $db; // CDatabase class to plug to - var $table; // Table with Nested Sets implemented - var $id; // Name of the ID-auto_increment-field in the table. - // These 3 variables are names of fields which are needed to implement - // Nested Sets. All 3 fields should exist in your table! - // However, you may want to change their names here to avoid name collisions. - var $left = 'cat_left'; - var $right = 'cat_right'; - var $level = 'cat_level'; - var $qryParams = ''; - var $qryFields = ''; - var $qryTables = ''; - var $qryWhere = ''; - var $qryGroupBy = ''; - var $qryHaving = ''; - var $qryOrderBy = ''; - var $qryLimit = ''; - var $sqlNeedReset = true; - var $sql; // Last SQL query - - //************************************************************************ - // Constructor - // $DB : CDatabase class instance to link to - // $tableName : table in database where to implement nested sets - // $itemId : name of the field which will uniquely identify every record - // $fieldNames : optional configuration array to set field names. Example: - // array( - // 'left' => 'cat_left', - // 'right' => 'cat_right', - // 'level' => 'cat_level' - // ) - function CDBTree(&$DB, $tableName, $itemId, $seq, $fieldNames = array()) - { - - if (empty($tableName)) trigger_error("phpDbTree: Unknown table", E_USER_ERROR); - - if (empty($itemId)) trigger_error("phpDbTree: Unknown ID column", E_USER_ERROR); - $this->seq = $seq; - $this->db = $DB; - $this->table = $tableName; - $this->id = $itemId; - - if (is_array($fieldNames) && sizeof($fieldNames)) - foreach($fieldNames as $k => $v) $this->$k = $v; - } - - //************************************************************************ - // Returns a Left and Right IDs and Level of an element or false on error - // $ID : an ID of the element - function getElementInfo($ID) - { - return $this->getNodeInfo($ID); - } - - function getNodeInfo($ID) - { - $this->sql = 'SELECT ' . $this->left . ',' . $this->right . ',' . $this->level . ' FROM ' . $this->table . ' WHERE ' . $this->id . '=\'' . $ID . '\''; -// print_r($this->sql); - - if (($query = $this->db->query($this->sql)) && ($this->db->num_rows($query) == 1) && ($Data = $this->db->fetch_array($query))) return array( - (int)$Data[$this->left], - (int)$Data[$this->right], - (int)$Data[$this->level] - ); - else trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); // throw new Exception(); - } - - //************************************************************************ - // Clears table and creates 'root' node - // $data : optional argument with data for the root node - function clear($data = array()) - { - // clearing table - - if ((!$this->db->query('TRUNCATE ' . $this->table)) && (!$this->db->query('DELETE FROM ' . $this->table))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - // preparing data to be inserted - - if (sizeof($data)) { - $fld_names = implode(',', array_keys($data)) . ','; - - if (sizeof($data)) $fld_values = '\'' . implode('\',\'', array_values($data)) . '\','; - } - $fld_names.= $this->left . ',' . $this->right . ',' . $this->level; - $fld_values.= '1,2,0'; - // inserting new record - $this->sql = 'INSERT INTO ' . $this->table . '(' . $fld_names . ') VALUES(' . $fld_values . ')'; - - if (!($this->db->query($this->sql))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - return $this->db->insert_id($this->seq); - } - - //************************************************************************ - // Updates a record - // $ID : element ID - // $data : array with data to update: array( => ) - function update($ID, $data) - { - $sql_set = ''; - - foreach($data as $k => $v) $sql_set.= ',' . $k . '=\'' . addslashes($v) . '\''; - return $this->db->query('UPDATE ' . $this->table . ' SET ' . substr($sql_set, 1) . ' WHERE ' . $this->id . '=\'' . $ID . '\''); - } - - //************************************************************************ - // Inserts a record into the table with nested sets - // $ID : an ID of the parent element - // $data : array with data to be inserted: array( => ) - // Returns : true on success, or false on error - function insert($ID, $data) - { - - if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - // preparing data to be inserted - - if (sizeof($data)) { - $fld_names = implode(',', array_keys($data)) . ','; - $fld_values = '\'' . implode('\',\'', array_values($data)) . '\','; - } - $fld_names.= $this->left . ',' . $this->right . ',' . $this->level; - $fld_values.= ($rightId) . ',' . ($rightId+1) . ',' . ($level+1); - // creating a place for the record being inserted - - if ($ID) { - $this->sql = 'UPDATE ' . $this->table . ' SET ' . $this->left . '=' . _case($this->left . '>' . $rightId, $this->left . '+2', $this->left) . ',' . $this->right . '=' . _case($this->right . '>=' . $rightId, $this->right . '+2', $this->right) . 'WHERE ' . $this->right . '>=' . $rightId; - - if (!($this->db->query($this->sql))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - } - // inserting new record - $this->sql = 'INSERT INTO ' . $this->table . '(' . $fld_names . ') VALUES(' . $fld_values . ')'; - - if (!($this->db->query($this->sql))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - return $this->db->insert_id($this->seq); - } - - //************************************************************************ - // Inserts a record into the table with nested sets - // $ID : ID of the element after which (i.e. at the same level) the new element - // is to be inserted - // $data : array with data to be inserted: array( => ) - // Returns : true on success, or false on error - function insertNear($ID, $data) - { - - if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - // preparing data to be inserted - - if (sizeof($data)) { - $fld_names = implode(',', array_keys($data)) . ','; - $fld_values = '\'' . implode('\',\'', array_values($data)) . '\','; - } - $fld_names.= $this->left . ',' . $this->right . ',' . $this->level; - $fld_values.= ($rightId+1) . ',' . ($rightId+2) . ',' . ($level); - // creating a place for the record being inserted - - if ($ID) { - $this->sql = 'UPDATE ' . $this->table . ' SET ' . $this->left . '=' . _case($this->left . '>' . $rightId, $this->left . '+2', $this->left) . $this->right . '=' . _case($this->right . '>' . $rightId, $this->right . '+2', $this->right) . 'WHERE ' . $this->right . '>' . $rightId; - - if (!($this->db->query($this->sql))) trigger_error("phpDbTree error:" . $this->db->error() , E_USER_ERROR); - } - // inserting new record - $this->sql = 'INSERT INTO ' . $this->table . '(' . $fld_names . ') VALUES(' . $fld_values . ')'; - - if (!($this->db->query($this->sql))) trigger_error("phpDbTree error:" . $this->db->error() , E_USER_ERROR); - return $this->db->insert_id($this->seq); - } - - //************************************************************************ - // Assigns a node with all its children to another parent - // $ID : node ID - // $newParentID : ID of new parent node - // Returns : false on error - function moveAll($ID, $newParentId) - { - - if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - - if (!(list($leftIdP, $rightIdP, $levelP) = $this->getNodeInfo($newParentId))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - - if ($ID == $newParentId || $leftId == $leftIdP || ($leftIdP >= $leftId && $leftIdP <= $rightId)) return false; - // whether it is being moved upwards along the path - - if ($leftIdP < $leftId && $rightIdP > $rightId && $levelP < $level-1) { - $this->sql = 'UPDATE ' . $this->table . ' SET ' - . $this->level . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level) . "," - . $this->right . '=' . _case($this->right . ' BETWEEN ' . ($rightId+1) . ' AND ' . ($rightIdP-1) , $this->right . '-' . ($rightId-$leftId+1) - , _case($this->left . ' BETWEEN ' . ($leftId) . ' AND ' . ($rightId) , $this->right . '+' . ((($rightIdP-$rightId-$level+$levelP) /2) *2+$level-$levelP-1) , $this->right)) . "," - . $this->left . '=' . _case($this->left . ' BETWEEN ' . ($rightId+1) . ' AND ' . ($rightIdP-1) , $this->left . '-' . ($rightId-$leftId+1) , _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . ($rightId) , $this->left . '+' . ((($rightIdP-$rightId-$level+$levelP) /2) *2+$level-$levelP-1) , $this->left)) . 'WHERE ' . $this->left . ' BETWEEN ' . ($leftIdP+1) . ' AND ' . ($rightIdP-1); - - } elseif ($leftIdP < $leftId) { - $this->sql = 'UPDATE ' . $this->table . ' SET ' - . $this->level . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level) . "," - . $this->left . '=' . _case($this->left . ' BETWEEN ' . $rightIdP . ' AND ' . ($leftId-1) , $this->left . '+' . ($rightId-$leftId+1) - , _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->left . '-' . ($leftId-$rightIdP) , $this->left)) . "," - . $this->right . '=' . _case($this->right . ' BETWEEN ' . $rightIdP . ' AND ' . $leftId, $this->right . '+' . ($rightId-$leftId+1) , _case($this->right . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->right . '-' . ($leftId-$rightIdP) , $this->right)) . 'WHERE ' . $this->left . ' BETWEEN ' . $leftIdP . ' AND ' . $rightId - // !!! added this line (Maxim Matyukhin) - . ' OR ' . $this->right . ' BETWEEN ' . $leftIdP . ' AND ' . $rightId; - } else { - $this->sql = 'UPDATE ' . $this->table . ' SET ' - . $this->level . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level) . "," - . $this->left . '=' . _case($this->left . ' BETWEEN ' . $rightId . ' AND ' . $rightIdP, $this->left . '-' . ($rightId-$leftId+1) - , _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->left . '+' . ($rightIdP-1-$rightId), $this->left)) . ", " - . $this->right . '=' . _case($this->right . ' BETWEEN ' . ($rightId+1) . ' AND ' . ($rightIdP-1) , $this->right . '-' . ($rightId-$leftId+1) , _case($this->right . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->right . '+' . ($rightIdP-1-$rightId) , $this->right)) . 'WHERE ' . $this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP - // !!! added this line (Maxim Matyukhin) - . ' OR ' . $this->right . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP; - } - return $this->db->query($this->sql) or trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - } - - // Перемещение всех детей ветки в другую ветку - function moveChildren($ID, $newParentId) - { - - if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - - if (!(list($leftIdP, $rightIdP, $levelP) = $this->getNodeInfo($newParentId))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - - if ($ID == $newParentId || $leftId == $leftIdP || ($leftIdP >= $leftId && $leftIdP <= $rightId)) return false; - // whether it is being moved upwards along the path - - if ($leftIdP < $leftId && $rightIdP > $rightId && $levelP < $level-1) { - // _update($this->table, array(), ) - $this->sql = 'UPDATE ' . $this->table . ' SET ' - // Меняем уровень - . $this->level . '=' . - _case(_between($this->left, $leftId, $rightId), - $this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level) - // Меняем границы - . $this->left . '=' . - _case(_beetween($this->left, $rightId+1, $rightIdP-1), $this->left . '-' . $rightId-$leftId+1 , - _case(_between($this->left, $leftId, $rightId), $this->left . '+' . ((($rightIdP-$rightId-$level+$levelP) /2) *2+$level-$levelP-1) , $this->left)) - . $this->right . '=' . - _case(_between($this->right, $rightId+1, $rightIdP-1), $this->right . '-' . ($rightId-$leftId+1) , - _case(_between($this->left, $leftId, $rightId), $this->right . '+' . ((($rightIdP-$rightId-$level+$levelP) /2) *2+$level-$levelP-1) , $this->right)) - . 'WHERE ' . _between($this->left, ($leftIdP+1), ($rightIdP-1)); - - } elseif ($leftIdP < $leftId) { - $this->sql = 'UPDATE ' . $this->table . ' SET ' - . $this->level . '=' . - _case(_between($this->left, $leftId, $rightId), - $this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level) - . $this->left . '=' . - _case(_between($this->left, $rightIdP, $leftId-1), $this->left . '+' . ($rightId-$leftId+1), - _case(_between($this->left, $leftId, $rightId), $this->left . '-' . ($leftId-$rightIdP) , $this->left)) - . $this->right . '=' . - _case(_between($this->right, $rightIdP, $leftId), $this->right . '+' . ($rightId-$leftId+1), - _case(_between($this->right, $leftId, $rightId), $this->right . '-' . ($leftId-$rightIdP) , $this->right)) - . 'WHERE ' . _between($this->left, $leftIdP, $rightId) - // !!! added this line (Maxim Matyukhin) - . ' OR ' . _between($this->right, $leftIdP, $rightId); - } else { - $this->sql = 'UPDATE ' . $this->table . ' SET ' - . $this->level . '=' - . _case(_between($this->left, $leftId, $rightId), - $this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level) - . $this->left . '=' . - _case(_between($this->left, $rightId, $rightIdP), $this->left . '-' . ($rightId-$leftId+1), - _case(_between($this->left, $leftId, $rightId), $this->left . '+' . ($rightIdP-1-$rightId), $this->left)) - . $this->right . '=' . - _case(_between($this->right, $rightId+1, $rightIdP-1), $this->right . '-' . ($rightId-$leftId+1), - _case(_between($this->right, $leftId, $rightId), $this->right . '+' . ($rightIdP-1-$rightId) , $this->right)) - . 'WHERE ' . _between($this->left, $leftId, $rightIdP) - // !!! added this line (Maxim Matyukhin) - . ' OR ' . _between($this->right, $leftId, $rightIdP); - } - return $this->db->query($this->sql) or trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - - } - - //************************************************************************ - // Deletes a record wihtout deleting its children - // $ID : an ID of the element to be deleted - // Returns : true on success, or false on error - function delete($ID) - { - - if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - // Deleting record - $this->sql = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->id . '=\'' . $ID . '\''; - - if (!$this->db->query($this->sql)) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - // Clearing blank spaces in a tree - $this->sql = 'UPDATE ' . $this->table . ' SET ' - . $this->left . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->left . '-1', $this->left) . ", " - . $this->right . '=' . _case($this->right . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->right . '-1', $this->right) . ", " - . $this->level . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->level . '-1', $this->level) . ", " - . $this->left . '=' . _case($this->left . '>' . $rightId, $this->left . '-2', $this->left) . ", " - . $this->right . '=' . _case($this->right . '>' . $rightId, $this->right . '-2', $this->right) - . ' WHERE ' . $this->right . '>' . $leftId; - - if (!$this->db->query($this->sql)) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - return true; - } - - //************************************************************************ - // Deletes a record with all its children - // $ID : an ID of the element to be deleted - // Returns : true on success, or false on error - function deleteAll($ID) - { - - if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - // Deleteing record(s) - $this->sql = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId; - - if (!$this->db->query($this->sql)) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - // Clearing blank spaces in a tree - $deltaId = ($rightId-$leftId) +1; - $this->sql = 'UPDATE ' . $this->table . ' SET ' - . $this->left . '=' . _case($this->left . '>' . $leftId, $this->left . '-' . $deltaId, $this->left) . ", " - . $this->right . '=' . _case($this->right . '>' . $leftId, $this->right . '-' . $deltaId, $this->right) - . ' WHERE ' . $this->right . '>' . $rightId; - - if (!$this->db->query($this->sql)) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - return true; - } - - //************************************************************************ - // Enumerates children of an element - // $ID : an ID of an element which children to be enumerated - // $start_level : relative level from which start to enumerate children - // $end_level : the last relative level at which enumerate children - // 1. If $end_level isn't given, only children of - // $start_level levels are enumerated - // 2. Level values should always be greater than zero. - // Level 1 means direct children of the element - // Returns : a result id for using with other DB functions - function enumChildrenAll($ID) - { - return $this->enumChildren($ID, 1, 0); - } - - function enumChildren($ID, $start_level = 1, $end_level = 1) - { - if ($start_level < 0) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - // We could use sprintf() here, but it'd be too slow - $whereSql1 = ' AND ' . $this->table . '.' . $this->level; - $whereSql2 = '_' . $this->table . '.' . $this->level . '+'; - - if (!$end_level) $whereSql = $whereSql1 . '>=' . $whereSql2 . (int)$start_level; - else { - $whereSql = ($end_level <= $start_level) ? $whereSql1 . '=' . $whereSql2 . (int)$start_level : ' AND ' . $this->table . '.' . $this->level . ' BETWEEN _' . $this->table . '.' . $this->level . '+' . (int)$start_level . ' AND _' . $this->table . '.' . $this->level . '+' . (int)$end_level; - } - $this->sql = $this->sqlComposeSelect(array( - '', // Params - '', // Fields - $this->table . ' _' . $this->table . ', ' . $this->table, // Tables - '_' . $this->table . '.' . $this->id . '=\'' . $ID . '\'' . ' AND ' . $this->table . '.' . $this->left . ' BETWEEN _' . $this->table . '.' . $this->left . ' AND _' . $this->table . '.' . $this->right . $whereSql - )); - return $this->db->query($this->sql); - } - - function enumChildrenArray($ID, $start_level = 1, $end_level = 1) - { - return $this->db->result2array($this->enumChildren($ID, $start_level, $end_level)); - } - - //************************************************************************ - // Enumerates the PATH from an element to its top level parent - // $ID : an ID of an element - // $showRoot : whether to show root node in a path - // Returns : a result id for using with other DB functions - function enumPath($ID, $showRoot = false) - { - $this->sql = $this->sqlComposeSelect(array( - '', // Params - '', // Fields - $this->table . ' _' . $this->table . ', ' . $this->table, // Tables - '_' . $this->table . '.' . $this->id . '=\'' . $ID . '\'' . ' AND _' . $this->table . '.' . $this->left . ' BETWEEN ' . $this->table . '.' . $this->left . ' AND ' . $this->table . '.' . $this->right . (($showRoot) ? '' : ' AND ' . $this->table . '.' . $this->level . '>0') , // Where - '', // GroupBy - '', // Having - $this->table . '.' . $this->left // OrderBy - - )); - return $this->db->query($this->sql); - } - - function enumPathArray($ID, $showRoot = false) - { - return $this->db->result2array($this->enumPath($ID, $showRoot)); - } - - //************************************************************************ - // Returns query result to fetch data of the element's parent - // $ID : an ID of an element which parent to be retrieved - // $level : Relative level of parent - // Returns : a result id for using with other DB functions - function getParent($ID, $level = 1) - { - - if ($level < 1) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); - $this->sql = $this->sqlComposeSelect(array( - '', // Params - '', // Fields - $this->table . ' _' . $this->table . ', ' . $this->table, // Tables - '_' . $this->table . '.' . $this->id . '=\'' . $ID . '\'' . ' AND _' . $this->table . '.' . $this->left . ' BETWEEN ' . $this->table . '.' . $this->left . ' AND ' . $this->table . '.' . $this->right . ' AND ' . $this->table . '.' . $this->level . '=_' . $this->table . '.' . $this->level . '-' . (int)$level // Where - - )); - $result = $this->db->result2array($this->db->query($this->sql)); - return (int)$result[0][$this->id]; - } - //************************************************************************ - - function sqlReset() - { - $this->qryParams = ''; - $this->qryFields = ''; - $this->qryTables = ''; - $this->qryWhere = ''; - $this->qryGroupBy = ''; - $this->qryHaving = ''; - $this->qryOrderBy = ''; - $this->qryLimit = ''; - return true; - } - - //************************************************************************ - function sqlSetReset($resetMode) - { - $this->sqlNeedReset = ($resetMode) ? true : false; - } - - //************************************************************************ - function sqlParams($param = '') - { - return (empty($param)) ? $this->qryParams : $this->qryParams = $param; - } - - function sqlFields($param = '') - { - return (empty($param)) ? $this->qryFields : $this->qryFields = $param; - } - - function sqlSelect($param = '') - { - return $this->sqlFields($param); - } - - function sqlTables($param = '') - { - return (empty($param)) ? $this->qryTables : $this->qryTables = $param; - } - - function sqlFrom($param = '') - { - return $this->sqlTables($param); - } - - function sqlWhere($param = '') - { - return (empty($param)) ? $this->qryWhere : $this->qryWhere = $param; - } - - function sqlGroupBy($param = '') - { - return (empty($param)) ? $this->qryGroupBy : $this->qryGroupBy = $param; - } - - function sqlHaving($param = '') - { - return (empty($param)) ? $this->qryHaving : $this->qryHaving = $param; - } - - function sqlOrderBy($param = '') - { - return (empty($param)) ? $this->qryOrderBy : $this->qryOrderBy = $param; - } - - function sqlLimit($param = '') - { - return (empty($param)) ? $this->qryLimit : $this->qryLimit = $param; - } - - //************************************************************************ - function sqlComposeSelect($arSql) - { - $joinTypes = array( - 'join' => 1, - 'cross' => 1, - 'inner' => 1, - 'straight' => 1, - 'left' => 1, - 'natural' => 1, - 'right' => 1 - ); - $this->sql = 'SELECT ' . $arSql[0] . ' '; - - if (!empty($this->qryParams)) $this->sql.= $this->sqlParams . ' '; - - if (empty($arSql[1]) && empty($this->qryFields)) $this->sql.= $this->table . '.' . $this->id; - else { - - if (!empty($arSql[1])) $this->sql.= $arSql[1]; - - if (!empty($this->qryFields)) $this->sql.= ((empty($arSql[1])) ? '' : ',') . $this->qryFields; - } - $this->sql.= ' FROM '; -// $tblAr = array(0 => 'join'); - $isJoin = ($tblAr = explode(' ', trim($this->qryTables))) - && /*($joinTypes[strtolower($tblAr[0]) ])*/ 1; - - if (empty($arSql[2]) && empty($this->qryTables)) $this->sql.= $this->table; - else { - - if (!empty($arSql[2])) $this->sql.= $arSql[2]; - - if (!empty($this->qryTables)) { - - if (!empty($arSql[2])) $this->sql.= (($isJoin) ? ' ' : ','); - elseif ($isJoin) $this->sql.= $this->table . ' '; - $this->sql.= $this->qryTables; - } - } - - if ((!empty($arSql[3])) || (!empty($this->qryWhere))) { - $this->sql.= ' WHERE ' . $arSql[3] . ' '; - - if (!empty($this->qryWhere)) $this->sql.= (empty($arSql[3])) ? $this->qryWhere : 'AND(' . $this->qryWhere . ')'; - } - - if ((!empty($arSql[4])) || (!empty($this->qryGroupBy))) { - $this->sql.= ' GROUP BY ' . $arSql[4] . ' '; - - if (!empty($this->qryGroupBy)) $this->sql.= (empty($arSql[4])) ? $this->qryGroupBy : ',' . $this->qryGroupBy; - } - - if ((!empty($arSql[5])) || (!empty($this->qryHaving))) { - $this->sql.= ' HAVING ' . $arSql[5] . ' '; - - if (!empty($this->qryHaving)) $this->sql.= (empty($arSql[5])) ? $this->qryHaving : 'AND(' . $this->qryHaving . ')'; - } - - if ((!empty($arSql[6])) || (!empty($this->qryOrderBy))) { - $this->sql.= ' ORDER BY ' . (isset($arSql[6]) ? $arSql[6] : '') . ' '; - - if (!empty($this->qryOrderBy)) $this->sql.= (empty($arSql[6])) ? $this->qryOrderBy : ',' . $this->qryOrderBy; - } - - if (!empty($arSql[7])) $this->sql.= ' LIMIT ' . $arSql[7]; - elseif (!empty($this->qryLimit)) $this->sql.= ' LIMIT ' . $this->qryLimit; - - if ($this->sqlNeedReset) $this->sqlReset(); - return $this->sql; - } - //************************************************************************ - -} diff --git a/core/tree/sort.php b/core/tree/sort.php deleted file mode 100644 index cefd3e3..0000000 --- a/core/tree/sort.php +++ /dev/null @@ -1,79 +0,0 @@ -sortBy($data, 'name'); - */ -class NestedSetSort { - private $data = array(); - private $result = array(); - private $sortBy = ''; - - public function __construct() { - } - - // Преобразуем Nested Set в дерево и сортируем - private function listTree(array $tree, $offset, $level) { - $result = array(); - for ($i = $offset; $i < sizeof($tree); $i++) { - $leaf = $tree[$i]; - $clevel = $leaf['cat_level']; - if ($clevel == $level) { - $result [] = array($i); - } else if ($clevel > $level) { - list($subtree, $i) = $this->listTree($tree, $i, $clevel); - $i--; - $result[sizeof($result) - 1][1] = $subtree; - } else { - $this->sortList($result, $tree); - return array($result, $i); - } - } - $this->sortList($result, $tree); - return array($result, $i); - } - - // Сравнение двух элементов - private function compare($a, $b) { - $a1 = $this->data[$a[0]][$this->sortBy]; - $b1 = $this->data[$b[0]][$this->sortBy]; - return strcmp($a1, $b1); - } - - // Сортировка списка - private function sortList(array &$list, $data) { - usort($list, array($this, 'compare')); - } - - // Создает дерево в виде списка - private function reorder(array $tree) { - foreach($tree as $node) { - $this->result[] = $this->data[$node[0]]; - if (isset($node[1])) { - $this->reorder($node[1]); - } - } - } - - public function sortBy0(array $data, $sortBy) - { - $this->data = $data; - $this->sortBy = $sortBy; - $order = $this->listTree($data, 0, 0); - return $order[0]; - } - - // Сортировка по заданному полю - public function sortBy(array $data, $sortBy) { - $this->data = $data; - $this->sortBy = $sortBy; - $order = $this->listTree($data, 0, 0); - $this->reorder($order[0]); - return $this->result; - } -} diff --git a/core/validator/rule/all.php b/core/validator/rule/all.php deleted file mode 100644 index 47006d7..0000000 --- a/core/validator/rule/all.php +++ /dev/null @@ -1,2 +0,0 @@ -_section [$section] = $view; - } - - public function jGrowl($message, $args) - { - $this->addScriptRaw('$.jGrowl("' . $message . '", ' . json::encode($args) . ");\n", true); - } - - public function setGlobal($name, $args) - { - $this->addScriptRaw("var " . $name . " = " . json::encode($args) . ";\n", false); - } - - /** - * Добавляет скипт к текущему шаблону - * - * @param string $name путь к скрипту - */ - public function addScript($name) - { - $this->_script [] = $name; - } - - /** - * Добавляет код скипта к текущему шаблону - * - * @param string $name строка javascript кода - */ - public function addScriptRaw($name, $startup = false) - { - if ($startup) { - $this->_startup [] = $name; - } else { - $this->_scriptstring [] = $name; - } - } - - /** - * Добавляет стили к текущему шаблону - * - * @param string $name путь к стилю - */ - public function addStyleSheet($name) - { - $this->_stylesheet [] = $name; - } - - /** - * Рекурсивно извлекает из значение свойства обьекта - * - * @param string $list Имя свойства - * @param boolean $flatten - */ - private function doTree($list, $flatten = true) { - $result = ($flatten == true) ? $this->$list : array($this->$list); - foreach ($this->_section as $key => $value) { - if (is_object($value)) $result = array_merge($value->doTree($list, $flatten), $result); - } - return $result; - } - - /** - * Массив имен файлов скриптов - * - * return array - */ - public function getScripts() - { - return $this->doTree('_script'); - } - - function resolveAlias($alias, $list) - { - $result = array(); - foreach($list as $item) { - $result [] = strtr($item, $alias); - } - return $result; - } - - /** - * Строка со скриптом - * - * @return string - */ - public function getScriptRaw() - { - return implode("\n", $this->doTree('_scriptstring')); - } - - public function getScriptStartup() - { - return implode("\n", $this->doTree('_startup')); - } - - /*abstract*/ public function set($key, $value) - { - } - - /** - * Массив имен файлов стилей - * - * return array - */ - public function getStyleSheet() - { - return $this->doTree('_stylesheet'); - } - - /** - * Обработка всех вложенных шаблонов - * - * @return string - */ - public function execute() - { - foreach ($this->_section as $key => $value) { - $this->set($key, (is_object($value)) ? $value->execute() : $value); // ? - } - } - - /** - * Установка заголовка шаблона - * - * @param string $title - */ - public function setTitle($title) - { - $this->_title = $title; - } - - private function isNotNull($title) - { - return $title !== null; - } - - /** - * Общая строка заголовка - */ - public function getTitle() - { - return implode(" - ", array_filter($this->doTree('_title', false), array($this, 'isNotNull'))); - } - - private function findGroup($groups, $file) - { - foreach($groups as $key => $group) { - if(in_array($file, $group)) { - return $key; - } - } - return false; - } - - private function groupFiles(array $list, $debug) - { - $debug = ($debug) ? 'debug=1' : ''; - $path = parse_url(WWW_PATH, PHP_URL_PATH); - $list = array_reverse($list); - // Группы нужно передвавать как параметр !!! - $groups = array( - 'table' => array($path . '/js/table.js', $path . '/js/listtable.js', - $path . '/js/page.js', $path . '/js/pagemenu.js'), - 'base' => array($path . '/js/admin.js', $path . '/js/cookie.js'), - ); - $use = array(); - - $result = array(); - foreach ($list as $file) { - $name = $this->findGroup($groups, $file); - if($name) { - $use [$name] = 1; - } else { - $result [] = $file; - } - } - $list = array(); - foreach ($use as $name => $value) { - $list [] = WWW_PATH . "/min/?$debug&f=" . implode(",", $groups[$name]); - } - return array_merge($list, $result); - } - - /** - * Обработка шаблона - * - * @return string - */ - public function render() - { - - $alias = $this->doTree('alias'); - -// require_once 'minify.php'; - // Скрипты и стили - $this->set('scripts', array_unique($this->groupFiles($this->resolveAlias($alias, $this->getScripts()), false))); - $this->set('stylesheet', array_unique($this->groupFiles($this->resolveAlias($alias, $this->getStyleSheet()), false))); - - $this->set('scriptstring', $this->getScriptRaw()); - $this->set('startup', $this->getScriptStartup()); - $this->set('title', $this->getTitle()); - // - return $this->execute(); // execute+phptal ?? - } - - function setAlias($alias) - { - $this->alias = $alias; - } - - function addAlias($name, $path) - { - $this->alias['${' . $name . '}'] = $path; - $this->set($name, $path); - } - - function loadImports($importFile) - { - // Подключение стилей и скриптов - if (file_exists($importFile)) { - $import = file_get_contents($importFile); - $files = explode("\n", $import); - foreach ($files as $file) { - if (strpos($file, ".js") !== false) { - $this->addScript(strtr(trim($file), $this->alias)); - } else if(strpos($file, ".css") !== false) { - $this->addStyleSheet(strtr(trim($file), $this->alias)); - } - } - } - } -} - -// CompositeView+PHPTAL -class View_Composite extends _View_Composite -{ - private $tal; - - function __construct($file) - { - parent::__construct($file); - - $this->tal = new PHPTAL($file); - $this->tal->setEncoding('WINDOWS-1251'); // PHP_TAL_DEFAULT_ENCODING !! - $this->tal->stripComments(true); - } - - function set($key, $val) - { - if ($key == 'title') { - $this->setTitle($val); - } - $this->tal->set($key, $val); - } - - function __set($key, $val) - { - $this->tal->set($key, $val); - } - - function setTranslator($tr) - { - $this->tal->setTranslator($tr); - } - - function execute() - { - parent::execute(); - // postProcess - return $this->tal->execute(); - } -} diff --git a/search/htmlhelper.php b/search/htmlhelper.php deleted file mode 100644 index 60f29f2..0000000 --- a/search/htmlhelper.php +++ /dev/null @@ -1,82 +0,0 @@ -]*?>.*?'si" => "", // strip out javascript - "'<[\/\!]*?[^<>]*?>'si" => "", // strip out html tags - "'([\r\n])[\s]+'" => "\\1", // strip out white space - "'&(quot|#34|#034|#x22);'i" => "\"", // replace html entities - "'&(amp|#38|#038|#x26);'i" => "&", // added hexadecimal values - "'&(lt|#60|#060|#x3c);'i" => ">", - "'&(gt|#62|#062|#x3e);'i" => "<", - "'&(nbsp|#160|#xa0);'i" => " ", - "'&(iexcl|#161);'i" => chr(161), - "'&(cent|#162);'i" => chr(162), - "'&(pound|#163);'i" => chr(163), - "'&(copy|#169);'i" => chr(169), - "'&(reg|#174);'i" => chr(174), - "'&(deg|#176);'i" => chr(176)); - $text = preg_replace(array_keys($search), array_values($search), $document); - return $text; -} - -/** - * Разделение текста на массив слов - */ -function tokenize ($document) -{ - $array = preg_split("/[\W]+/", $document); - return $array; -} - - -/** - * Ищет один из символов с конца строки - * - * @param string $haystack - * @param array $needle Массив символов для поиска - * @param int $offset Смещение от начала строки - * - * @return int Позицию первого совпадения - */ -function indexRight ($haystack, $needle, $offset = 0) -{ - if ((bool)$offset === false) $offset = 0; - while ($offset >= 0) { - if (in_array ($haystack[$offset], $needle)) { - return $offset; - } - $offset --; - } - return false; -} - -/** - * Ищет один из символов с начала строки - * - * @param string $haystack - * @param array $needle Массив символов для поиска - * @param int $offset Смещение от начала строки - * - * @return int Позицию первого совпадения - */ -function indexLeft ($haystack, $needle, $offset = 0) -{ - if ($offset < 0) return false; - while ($offset < strlen($haystack)) { - if ((is_callable($needle) && call_user_func ($needle, $haystack[$offset])) - || (is_array ($needle) && in_array ($haystack[$offset], $needle))) { - return $offset; - } - $offset ++; - } - return false; -} - -function not_ctype_alpha ($ch) -{ - return !ctype_alpha($ch); -} diff --git a/search/index.php b/search/index.php deleted file mode 100644 index 0d4cc9e..0000000 --- a/search/index.php +++ /dev/null @@ -1,84 +0,0 @@ -]*?>(.*?)'si"; - preg_match($title, $content, $matches); - if(isset($matches[1])) { - return $matches[1]; - } - return ""; - } - - // Выбираем основу слова - function clean ($word) - { - return Stemmer::russian(strtolower($word)); - } - - function process ($base, $files) - { - $path = new Path($base); - // Список документов - foreach ($path->getContentRec($files) as $file) { - $content = file_get_contents ($file); - $text = stripText($content); -// $title = self::getTitle ($content); - $title = pathinfo($file, PATHINFO_BASENAME); -// echo $file, "\n"; - // Список слов в документе - $list = tokenize($text); - foreach ($list as $word) { - $preword = self::clean($word); - if (isset($this->index[$preword])) { - $index = $this->index[$preword]; - if ( ! in_array ($this->count, $index)) $this->index[$preword] [] = $this->count; - } else { - // Не записываем слова длинна которых меньше 2 - if (strlen($preword) > 1) { - $this->index[$preword] = array ($this->count); - } - } - } - $this->text [] = array ($title, $path->relPath ($file), $text); - $this->count ++; - } - ksort($this->index); - } - - /** - * Сохранение результата поиска - */ - function saveData ($file) - { - $file = fopen($file, "w"); - // Количество слов и текстов - fwrite ($file, pack("SS", count($this->index), count($this->text))); - foreach ($this->index as $word => $value) { - $length = strlen($word); - array_unshift ($value, "SSa*S*", $length, count($value), $word); - fwrite($file, call_user_func_array ('pack', $value)); - } - - foreach ($this->text as $text) { - fwrite($file, pack("SSSa*a*a*", - strlen($text[0]), strlen($text[1]), strlen($text[2]) - , $text[0], $text[1], $text[2])); - } - } -} diff --git a/search/lexer.php b/search/lexer.php deleted file mode 100644 index b555006..0000000 --- a/search/lexer.php +++ /dev/null @@ -1,91 +0,0 @@ -src = $src; - $this->offset; - } - - private function skipSpace () - { - while (!$this->isEOL() && $this->getChar() == " ") { - $this->offset++; - } - } - - private function getChar () - { - return $this->src [$this->offset]; - } - - /** - * Проверяет на конец строки - */ - private function isEOL () { - return $this->offset >= strlen($this->src); - } - - /** - * Односимвольный токен - */ - private function easyToken () { - $ch = $this->getChar (); - switch ($ch) { - case '~': $token = array(self::TOKEN_NOT, $ch); break; - case '|': $token = array(self::TOKEN_OR, $ch); break; - case '(': $token = array(self::TOKEN_LPAREN, $ch); break; - case ')': $token = array(self::TOKEN_RPAREN, $ch); break; - case '&': $token = array(self::TOKEN_AND, $ch); break; - default: - $this->offset++; - $token = $this->getToken(); - } - $this->offset++; - return $token; - } - - /** - * Возвращает следующий токен - */ - public function getToken () - { - $this->skipSpace (); - if ($this->isEOL()) { - return array(self::TOKEN_EOL, ""); - } - if (ctype_alpha($this->getChar())) { - $start = $this->offset; - while (!$this->isEOL() && ctype_alpha($this->getChar())) { - $this->offset ++; - } - return array(self::TOKEN_WORD, substr ($this->src, $start, $this->offset-$start)); - } - return $this->easyToken(); - } - - public function nextToken () - { - $this->token = $this->getToken(); - } -} diff --git a/search/search.php b/search/search.php deleted file mode 100644 index d2b6266..0000000 --- a/search/search.php +++ /dev/null @@ -1,97 +0,0 @@ -lexer = new Lexer(); - $this->index = $index; - - $this->op = array ($this, 'Op'); - $this->binary = array ($this, 'binaryOp'); - $this->union = array ($this, 'union'); - $this->intersection = lcurry($this->op, 'array_uintersect', $this->union); - - $this->notQuery = lcurry ($this->binary, Lexer::TOKEN_NOT, - lcurry($this->op, 'array_udiff', 'array_udiff'), array ($this, 'easyQuery')); - - $this->orQuery = lcurry ($this->binary, Lexer::TOKEN_OR, - lcurry($this->op, $this->union, $this->union), $this->notQuery); - - $this->andQuery = lcurry ($this->binary, Lexer::TOKEN_AND, $this->intersection, $this->orQuery); - } - - function union ($a, $b, $callback) - { - return array_merge($a, $b); - } - - function Eq ($a, $b) - { - return $a == $b; - } - - function Op ($files, $words, $a, $b) { - return array ( - 'words' => call_user_func ($words, $a['words'], $b['words'], array ($this, 'eq')), - 'files' => call_user_func ($files, $a['files'], $b['files'], array ($this, 'eq')) - ); - } - - public function getQuery ($source) - { - $this->lexer->setSource ($source); - $this->lexer->nextToken(); - return $this->topQuery(); - } - - function topQuery () - { - $result = call_user_func ($this->andQuery); - while ($this->lexer->token[0] == Lexer::TOKEN_LPAREN) { - $result = call_user_func ($this->intersection, $result, call_user_func ($this->andQuery)); - } - return $result; - } - - function easyQuery () - { - $result = null; - if ($this->lexer->token[0] == Lexer::TOKEN_LPAREN) { - $this->lexer->nextToken (); - $result = $this->topQuery (); - if ($this->lexer->token[0] == Lexer::TOKEN_RPAREN) { - $this->lexer->nextToken (); - } - return $result; - } else { - $result = call_user_func ($this->index, $this->lexer->token[1]); - $this->lexer->nextToken (); - return $result; - } - } - - /** - * @param int $type Тип лексемы - * @param function $op Функция при совпадении типа лексемы при запросе - * @param function $next Следующий обработчик запроса - */ - function binaryOp ($type, $op, $next) - { - $result = call_user_func($next); - while ($this->lexer->token[0] == $type) { - $this->lexer->nextToken(); - $result = call_user_func($op, $result, call_user_func ($next)); - } - return $result; - } -} - diff --git a/search/searcher.php b/search/searcher.php deleted file mode 100644 index c320809..0000000 --- a/search/searcher.php +++ /dev/null @@ -1,101 +0,0 @@ -search = new Search (array ($this, 'getWord')); - } - - /** - * Читает содержимое индексного файла - * - * @param string $file Имя файла - */ - function setSource ($fileName) - { - $file = fopen($fileName, "r"); - $words = fread($file, 4); - $all = unpack("Swords/Stexts", $words); - for ($i = 0; $i < $all['words']; $i++) { - $pos = fread($file, 4); - $size = unpack("Sword/Sindex", $pos); - - $word = fread($file, $size['word']); - $index = unpack("S*", fread($file, $size['index']*2)); - $this->index[$word] = $index; - } - - for ($i = 0; $i < $all['texts']; $i++) { - $pos = fread($file, 6); - $size = unpack("Stitle/Surl/Stext", $pos); - // - $title = fread($file, $size['title']); - $url = fread($file, $size['url']); - $text = fread($file, $size['text']); - $this->text [] = array ($title, $url, $text); - } - } - - // По слову возвращаем список файлов и слово - public function getWord ($word) - { - $preword = Stemmer::russian($word); // Index?? -> clean - if (isset($this->index[$preword])) { // Search?? - return array ('files' => $this->index[$preword], 'words' => array ($preword)); - } - return array ('files' => array (), 'words' => array ()); - } - - /** - * Список документов в которых встечается слово - * - */ - function getResult (&$query) - { - $result = array (); - $word = $query['words']; - $list = $query['files']; - // - foreach ($list as $n) { - $result [] = array ( - 'title' => $this->text[$n][0], - 'file' => $this->text[$n][1], - 'text' => self::getSlice ($word[0], $this->text[$n][2])); - } - return $result; - } - - /** - * Часть документа в котором встречается слово - * - * @param $word Слово - * @param $text Текст содержащий слово - */ - function getSlice ($word, $text) - { - $pos = stripos($text, $word); - $offset = max(max ($pos-100, indexRight($text, array ("."), $pos) + 1), 0); - $real = substr($text, $pos, strlen($word)) ; - return substr($text, $offset, $pos - $offset) - . "" . $real . "" . substr ($text, $pos + strlen($word), 100); - } - - /** - * Поиск по запросу - * - */ - function search ($query) - { - $result = $this->search->getQuery($query); - return $this->getResult($result); - } -} - diff --git a/search/stemmer.php b/search/stemmer.php deleted file mode 100644 index f3bee01..0000000 --- a/search/stemmer.php +++ /dev/null @@ -1,180 +0,0 @@ -adaptee)) { - return $this->adaptee [$name]; + return $this->adaptee[$name]; } else { return $this->adaptee->$name; } diff --git a/core/arr.php b/src/Arr.php similarity index 100% rename from core/arr.php rename to src/Arr.php diff --git a/core/collection.php b/src/Collection.php similarity index 91% rename from core/collection.php rename to src/Collection.php index 5ab61ec..467175e 100644 --- a/core/collection.php +++ b/src/Collection.php @@ -1,8 +1,7 @@ data[$key] = $value; } @@ -54,7 +53,7 @@ class Collection implements ArrayAccess */ public function get($key, $default = null) { - return isset($this->data[$key]) ? $this->data[$key] : $default; + return isset($this->data[$key]) && $this->data[$key] != '' ? $this->data[$key] : $default; } public function getInt($key, $default = 0) diff --git a/core/connection/httpconnection.php b/src/Connection/HttpRequest.php similarity index 71% rename from core/connection/httpconnection.php rename to src/Connection/HttpRequest.php index b2b25f3..28d0515 100644 --- a/core/connection/httpconnection.php +++ b/src/Connection/HttpRequest.php @@ -1,7 +1,6 @@ method = self::GET; + } /** * Возвращает заголовок соединения */ public function getHeader() { - $result = $this->method . " " . $this->url . " HTTP/1.1\r\n"; + $result = $this->method . " " . $this->url . " " . $this->http_version . "\r\n"; $result .= "Host: ". $this->host ."\r\n"; foreach ($this->param as $key => $value) { $result .= $key . ": " . $value . "\r\n"; @@ -75,10 +79,10 @@ class HttpConnection { $host = ($this->proxy_host) ? $this->proxy_host : $this->host; $port = ($this->proxy_port) ? $this->proxy_port : $this->port; + $errno = 0; + $errstr = ''; $socket = fsockopen($host, $port, $errno, $errstr, 30); - if (! $socket) { - return null; // Exception - } else { + if (is_resource($socket)) { $header = $this->getHeader(); fwrite($socket, $header); @@ -91,5 +95,17 @@ class HttpConnection } return null; } + + static function getJSON($url, $data) { + $c = new Connection_HttpRequest(); + $c->http_version = "HTTP/1.0"; + + $query = http_build_query($data); + $c->setUrl($q = $url . '?' . $query); + $page = $c->getPage(); + + $response = new Connection_HttpResponse($page); + return json_decode((string) preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $response->getData()), true); + } } diff --git a/core/connection/httpconnectionresponse.php b/src/Connection/HttpResponse.php similarity index 95% rename from core/connection/httpconnectionresponse.php rename to src/Connection/HttpResponse.php index eef78f6..9e94c9f 100644 --- a/core/connection/httpconnectionresponse.php +++ b/src/Connection/HttpResponse.php @@ -3,11 +3,14 @@ /** * Обрабатывает HTTP ответ */ -class HttpConnectionResponse +class Connection_HttpResponse { private $offset; private $param = array (); private $code; + public $response; + public $version; + public $data; public function __construct($response) { diff --git a/src/Controller/Action.php b/src/Controller/Action.php new file mode 100644 index 0000000..4ddeb58 --- /dev/null +++ b/src/Controller/Action.php @@ -0,0 +1,414 @@ +path = new Widgets_PathMenu(); + } + + public function setUp() { + } + + public function loadConfig($name) { + $filename = Shortcut::getUrl('config', $name); + if (file_exists($filename)) { + include($filename); + } else { + throw new Exception('Невозможно загрузить файл настроек ' . $name); + } + return $settings; + } + + public function getConnection() + { + return $this->db; + } + + public function installPath($name) + { + return Path::join(CMS_PATH, "modules", $name); + } + + public function addSuggest(View_View $view, $name) + { + $suggest = array(); + $file = Path::join($this->viewPath, 'help', $name . '.suggest'); + if (file_exists($file)) { + include($file); + $view->suggestions = $suggest; + } + } + + function findIcon($icon, $size) + { + return Path::join($this->iconPath, $size . 'x' . $size, $icon . '.png'); + } + + /** + * Создает представление + * @param $name String + * @param $viewClass String + * @return View_Composite + */ + public function getView($name, $viewClass = 'View_Composite') + { + $file = $name . self::TEMPLATE_EXTENSION; + + $list = array( + Path::join($this->viewPath, TEMPLATES, $this->viewPathPrefix) => Path::join(WWW_PATH, "modules", $this->name, TEMPLATES, $this->viewPathPrefix), + Path::join(CMS_PATH, "templates") => Path::join(WWW_PATH, "templates") + ); + + // Поиск файла для шаблона + foreach($list as $ospath => $path) { + $template = Path::join($ospath, $file); + if(file_exists($template)) { break; } + } + + /*.View_Composite.*/$tpl = new $viewClass($template); + + $tpl->set('icons', $this->iconPath); // Путь к файлам текущей темы + $tpl->set('media', $this->themePath); // Путь к файлам текущей темы + $tpl->set('assets', Path::join(WWW_PATH, "assets", "css")); + $tpl->set('script', $this->jsPath); // Путь к файлам скриптов + $tpl->set('template', $path); // Путь к файлам текущего шаблона + + $tpl->setAlias(array( + 'icons' => $this->iconPath, + 'script' => $this->jsPath, + // Для media и template поиск происходит как для файлов шаблонов + 'media' => $list, + 'template' => $list + )); + + $tpl->loadImports(Path::skipExtension($template) . ".import"); + + $this->addSuggest($tpl, $name); + return $tpl; + } + + public function getModel($name) + { + if (!$this->factory) { + $this->factory = new Model_Factory($this->db, $this->_registry); + } + return $this->factory->getModel($name); + } + + /** + * Выбор действия + * Т.к действия являются методами класса то + * 1. Можно переопределить действия + * 2. Использовать наследование чтобы добавить к старому обработчику новое поведение + * @param $request Обьект запроса + */ + public function execute1(HttpRequest $request) + { + $action = self::ACTION_PREFIX . ucfirst($request->getAction()); + if (!method_exists($this, $action)) { + $action = "actionIndex"; + } + $view = $this->forward($action, $request); + if ($view instanceof View_View) { + $view->active_module = get_class($this); + $view->module_action = $action; + } + return $view; + } + + public function execute(HttpRequest $request) + { + $result = $this->execute1($request); + if (!empty($result)) { + $this->view = $result; + } + $text = $this->render(); + return $text; + } + + public function forward($action, HttpRequest $args) { + $value = call_user_func(array($this, $action), $args); + return $value; + } + + /** + * Страница по умолчанию + */ + public function actionIndex(HttpRequest $request) { + return ""; + } + + public function postUrl($name, $param) + { + $uri = array_merge(array('module' => + strtr($this->modulePrefix . strtolower(get_class($this)), array('module_' => '')), "action" => $name), + $this->param, $param); + + return "?" . http_build_query($uri); + } + + /** + * Генерация ссылки c учетом прав пользователя на ссылки + * @param string $name Действие + * @param array $param Дополнительные параметры + * 'mode' означает что элемент до отправки обрабатывается javascript + * @return array|null + */ + public function nUrl($name, array $param = array()) + { + /*.Filter_ActionAccess.*/$access = $this->access; + if ($access != null || $access->checkAction($name)) { + return lcurry(array($this, 'postUrl'), $name, $param); + } + return null; + } + + public function fUrl($name, array $param = array()) + { + return forceUrl($this->nUrl($name, $param)); + } + + /** + * Добавляет параметр для всех ссылок создаваемых функцией nUrl, aUrl + */ + public function addParameter($name, $value) + { + if ($value) { + $this->param [$name] = $value; + } + } + + /** + * Генерация ссылки на действие контроллера + * Ajax определяется автоматически mode = ajax используется для смены layout + * @param $name + * @param array $param + * @return array|null + * + * @example ?action=$name&mode=ajax + * {$param[i].key = $param[i].value} + */ + public function aUrl($name, array $param = array()) + { + return $this->nUrl($name, array_merge(array('mode' => 'ajax'), $param)); // FIXME + } + + /** + * Добавление помошника контроллера + */ + public function addHelper($class) + { + $this->helpers [] = $class; + } + + /** + * Вызов помошников контроллера + */ + public function callHelpers(HttpRequest $request) + { + $action = self::ACTION_PREFIX . $request->getAction(); + foreach ($this->helpers as $helper) { + if (method_exists($helper, $action)) { + return call_user_func(array($helper, $action), $request, $this); + } else { + return $helper->actionIndex($request, $this); // Вместо return response ??? + } + } + } + + /** + * Загрузка файла класса + */ + public function loadClass($path, $setup = null, $prefix = '') + { + if (file_exists($path)) { + require_once ($path); + $class = $prefix . pathinfo($path, PATHINFO_FILENAME); + return new $class($setup); + } + throw new Exception("NO CLASS $path"); + } + + public function loadSettings($path) + { + $result = new Settings($path); + $result->read(); + return $result->export(); + } + + // Для Widgets + public $view = null; + public $childNodes = array(); + public $ctrlValues = array(); + public $childViews = array(); + + public function setView($name) + { + $this->view = $this->getView($name); + } + + /** + * Установка заголовка для отображения + */ + public function setTitle($title) + { + $this->view->setTitle($title); + } + + /** + * Добавление widget к отображению + */ + public function addChild(/*Widget*/ $section, $node) + { + $this->childNodes[$section] = $node; + } + + public function setValue(/*Widget*/ $name, $value) + { + $this->ctrlValues[$name] = $value; + } + + /** + * Добавление дочернего отображения к текущему отображению + */ + public function addView(/*CompositeView*/ $section, $node) + { + $this->childViews[$section] = $node; + } + + /** + * Генерация содержания + * Путаница c execute и render + */ + public function render() + { + if ($this->view instanceof View_View) { + $this->view->assignValues($this->ctrlValues); + + foreach ($this->childNodes as $name => $node) { + $node->make($this); + $this->view->setView($name, $node->view); + } + foreach ($this->childViews as $name => $node) { + $this->view->setView($name, $node); + } + } + return $this->view; + } + + function getPageId(HttpRequest $request) + { + $pageId = time(); + $request->session()->set('page', $pageId); + return $pageId; + } + + function checkPageId(HttpRequest $request, $page) + { + if ($request->get('__forced__')) { + return true; + } + $_page = $request->session()->get('page'); + $result = ($_page && $_page == $page); + $request->session()->clean('page'); + return $result; + } + + function _getActionPath() + { + return new Controller_State('index'); + } + + // Тоже убрать в метод Controller_Model + function getActionPath(HttpRequest $request, $action = null) + { + $this->_getActionPath()->getPath($this, ($action) ? $action : $request->getAction()); + } + + function addFilePathToPath($filePath, $type) + { + $pathToItem = $this->directoryPath($filePath, $type, 'default'); + $this->path->addMenuItems($pathToItem['path']); + } + + function directoryPath($path, $type, $action) + { + $path = empty($path) ? '/' : $path; + + $base = new Path($path); + $parts = $base->getParts(); + + $_path = '/' . implode('/', $parts); + + $rs = new Model_Resources($this->db); + $section_path = $rs->getSectionByPath($_path, $type); + + $pathMenu = new Widgets_PathMenu(); + $pathMenu->addTitle('title'); + $modules = ['image' => 'images','page' => 'pages','document' => 'documents','media' => 'videos']; + + while ($section_path->id_parent) { + $_path = '/' . implode('/', $parts); + $pathMenu->addMenuItem( + forceUrl($this->nUrl('', array('module'=>$modules[$type],'action' => $action, 'mode' => 'ajax', 'path' => $_path))), + $section_path->title + ); + $section_path = $rs->getSectionById($section_path->id_parent); + array_pop($parts); + } + + $pathMenu->addMenuItem( + forceUrl($this->nUrl('', array('module'=>$modules[$type],'action' => $action, 'mode' => 'ajax', 'path' => '/'))), + $this->moduleTitle + ); + return $pathMenu->getItemsReverse(); + } + +} diff --git a/src/Controller/Component.php b/src/Controller/Component.php new file mode 100644 index 0000000..0a8220c --- /dev/null +++ b/src/Controller/Component.php @@ -0,0 +1,325 @@ +]*>/u', 'replaceContent', $text); +} + +class ComponentRequest { + public $component_id; + public $r; + + function __construct($c, HttpRequest $r) { + $this->component_id = $c; + $this->r = $r; + } + + function get($key, $default = null) { + if ($key == 'active_page') { + return $this->r->get($key); + } + if ($arr = $this->r->get($key)) { + if (is_array($arr)) { + return Arr::get($arr, $this->component_id, $default); + } else { + return $arr; + } + } + return $default; + } + + function getAction() { + return $this->r->getAction(); + } +} + +/** + * Класс компонента + */ +class Controller_Component +{ + public $viewPath = array(); + public $webPath = array(); + + public $template = null; + public $templatePath; + + public $component_id; + public $COMPONENTS_WEB; + + public /*.Settings.*/$registry; + public /*.Database.*/$db; + public /*.Collection.*/$parameter; + + public $module; + public $item_module; + + function before() { + } + + function get($request, $key, $default) { + } + + function execute(HttpRequest $request, $has_id = true) { + $crequest = new ComponentRequest($this->component_id, $request); + $action = 'action' . ucfirst($request->get('action', 'index')); + + $this->before(); + if (method_exists($this, $action)) { + return call_user_func(array($this, $action), $crequest); + } else { + return $this->actionIndex($crequest); + } + } + + public function getView($name) + { + // + /*.Settings.*/$registry = $this->registry; + $template = ($this->template) ? $this->template : $registry->readKey(array('system', 'template')); + + $selected = null; + foreach ($this->viewPath as $index => $viewPath) { + // Загружать шаблон по умолчанию если не найден текущий + if(is_dir(Path::join($this->viewPath[$index], 'templates', $template))) { + $tpl = new PHPTAL(Path::join($this->viewPath[$index], 'templates', $template, $name)); + $tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION); + $selected = $index; + break; + } + } + + if ($selected === null) { + $tpl = new PHPTAL(Path::join($this->viewPath[0], 'templates', 'modern', $name)); + $tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION); + $template = 'modern'; + $selected = 0; + } + + $tpl->stripComments(true); + $tpl->addPreFilter(new PHPTAL_PreFilter_Normalize()); + + $tpl->set('common', Path::join(WWW_PATH, '../', 'common')); + $tpl->set('script', Path::join(WWW_PATH, 'js')); + $tpl->set('media', Path::join(TEMPLATE_WEB, $template)); + $tpl->set('site_template', SITE_WWW_PATH . '/templates' . $registry->readKey(array('system', 'template'))); + $tpl->set('base', SITE_WWW_PATH); + + $tpl->set('component_base', $this->webPath[$selected]); + $tpl->set('component', Path::join($this->webPath[$selected], 'templates', $template)); + $tpl->set('component_id', $this->component_id); + + return $tpl; + } + + public function getTemplatePath($name) { + return Path::join($this->viewPath[0], 'templates', 'modern', $name); + } + + public function getTemplateWebPath() + { + return Path::join($this->webPath[0], 'templates', 'modern'); + } + + /** + * @param $name Имя модели + */ + private function getModelPath($name) + { + return Path::join (CMS_PATH, "model", $name . ".php"); + } + + /** + * Создает модель + * @param string $name + * @return model + */ + public function getModel($name) + { + require_once ($this->getModelPath ($name)); + $modelName = $name . "Mapper"; + $model = new $modelName (); + $model->db = $this->db; + return $model; + } + + public function options($key, $val, /*.Database_PDOStatement.*/$res) { + $result = array(); + while($res->next()) { + $result[] = array('value' => $res->getString($key), 'name' => $res->getString($val)); + } + return $result; + } + + public function optionsPair($list, $selected = false) { + $result = array(); + foreach ($list as $key => $value) { + $result [] = array('value' => $key, 'name' => $value, 'selected' => $key == $selected); + } + return $result; + } + + function getInfo() { + $filename = Path::join($this->viewPath[0], 'install.json'); + if (file_exists($filename)) { + $settings = json_decode(file_get_contents($filename), true); + return $settings; + } + return array(); + } + + /** + * Генерация интерфейса для выбора галлереи фотографии + */ + public function setParameters(/*.View_Composite.*/$view) + { + $form = new Form_Form(); + $options = new OptionFactory($this->db); + + $settings = $this->getInfo(); + $form->addFieldList($settings['parameter'], $options); + + $view->form = $form; + $view->component = $settings['component']; + $view->component_title = $settings['title']; + } + + static function loadComponent($expression, Database $db, Settings $registry) + { + + $expression = htmlspecialchars_decode($expression); + $offset = strpos($expression, '?'); + $url = parse_url($expression); + + $arguments = array(); + if ($offset === false) { + $path = $expression; + } else if (is_int($offset)) { + $path = substr($expression, 0, $offset); + $query = substr($expression, $offset + 1); + parse_str($query, $arguments); + } + $name = $path; + + $path = Path::join (BASE_PATH, 'components', $name, $name . '.php'); + $className = 'Component_' . $name; + + if (file_exists($path)) { + require_once ($path); + + $component = new $className(); + $component->db = $db; + $component->registry = $registry; + + $component->viewPath = array(BASE_PATH . '/components/' . $name . '/'); + $component->webPath = array(SITE_WWW_PATH . '/components/' . $name); + + $component->COMPONENTS_WEB = SITE_WWW_PATH . '/components/'; + + } else { + $path = Path::join (COMPONENTS, $name, $name . '.php'); + require_once ($path); + $component = new $className(); + $component->db = $db; + $component->registry = $registry; + + $component->viewPath = array(COMPONENTS . '/' . $name . '/', BASE_PATH . '/components/' . $name . '/'); + if (defined('COMPONENTS_WEB')) { + $component->webPath = array(COMPONENTS_WEB . '/' . $name, SITE_WWW_PATH . '/components/' . $name); + $component->COMPONENTS_WEB = COMPONENTS_WEB; + } + } + + $stmt = $db->prepareStatement("SELECT * FROM component WHERE code = ?"); + $stmt->setString(1, $expression); + $cid = $stmt->executeQuery(); + if ($cid->next()) { + $component->component_id = $cid->getInt('id_component'); + } else { + $last = $db->getIdGenerator(); + if ($last->isBeforeInsert()) { + $result = $last->getId('component_id_component_seq'); + + $stmt = $db->prepareStatement("INSERT INTO component (id_component, code) VALUES ($result, ?)"); + $stmt->setString(1, $expression); + $stmt->executeQuery(); + } + if ($last->isAfterInsert()) { + $stmt = $db->prepareStatement("INSERT INTO component (code) VALUES (?)"); + $stmt->setString(1, $expression); + $stmt->executeQuery(); + + $result = $last->getId('component_id_component_seq'); + } + $component->component_id = $result; + } + + $params = new Collection(); + $params->import(array_merge($_GET, $arguments)); + $component->parameter = $params; + $component->template = $params->get('template', false); + + global $componentsConfig; + $editor = $component->getEditUrl(); + if ($editor) { + $componentsConfig[] = $editor; + } + + return $component; + } + + function getEditUrl() { + return null; + } + + function raw_query(/*.ComponentRequest.*/ $request) + { + $arr = $request->r->export('get'); + + $param = array(); + /*.Collection.*/$parameter = $this->parameter; + foreach($parameter->export() as $key => $value) { + $param[$key] = $value; + } + + $data = array(); + foreach($arr as $key => $value) { + if (is_array($value)) { + $data[$key] = Arr::get($value, $this->component_id); + } else { + $data[$key] = $value; + } + } + $data['param'] = $param; + return $data; + } + + + function query(/*.ComponentRequest.*/ $request, $list) + { + $arr = $request->r->export('get'); + + foreach($list as $key => $val) { + $arr[$key] [$this->component_id] = $val; + } + + unset($arr['active_page']); + return '?' . http_build_query($arr); + } + + function addRequireJsPath($name, $path, $shim = null) { + global $requireJsConfig; + $requireJsConfig['paths'][$name] = $path; + if ($shim) { + $requireJsConfig['shim'][$name] = $shim; + } + } + + function actionIndex(/*.ComponentRequest.*/ $request) { + } +} + diff --git a/core/controller/frontcontroller.php b/src/Controller/Front.php similarity index 58% rename from core/controller/frontcontroller.php rename to src/Controller/Front.php index c88d74e..38b1a40 100644 --- a/core/controller/frontcontroller.php +++ b/src/Controller/Front.php @@ -1,32 +1,38 @@ _registry = $_registry; - $this->_shortcut = $_shortcut; + $this->_shortcut = $_shortcut; // $cc->newShortcut(); - $this->db = Database::getConnection($registry->readKey(array('system', 'dsn'))); - $this->installer = new Installer($_registry); + $dsn = $registry->readKey(array('system', 'dsn')); + $this->db = Database::getConnection($dsn); // $cc->newConnection(); } + public function isLoaded($name) + { + return isset($this->modules[$name]); + } /** * Создает экземпляр модуля и выполняет действия для него @@ -34,17 +40,22 @@ class Controller_Front extends Controller * @param request $request Имя модуля * @return string */ - public function loadModule($name, Collection $request) + public function loadModule($name, Collection $request, $controller = false) { - $this->installer->setUp($this->db, array($this, 'installPath')); - $this->installer->doUpdates($name); // ModuleLoader (1) + if ($this->isLoaded($name)) { + $module = $this->modules[$name]; + return $module->access->execute($request); + } - $moduleFile = Shortcut::getUrl($this->shortcut, $name); // ModuleLoader (2) - $module = $this->loadClass($moduleFile); + if ($controller) { + $moduleFile = Shortcut::getUrl($this->shortcut, $name, $controller); // ModuleLoader (2) + } else { + $moduleFile = Shortcut::getUrl($this->shortcut, $name, $name); // ModuleLoader (2) + } + $module = $this->loadClass($moduleFile, null, 'Module_'); if ($module) { // Инициализация модуля -// $module->viewPath = dirname($moduleFile); $module->viewPath = Shortcut::getUrl('modulepath', $name); $module->name = $name; @@ -59,15 +70,17 @@ class Controller_Front extends Controller $module->db = $this->db; // Не для всех приложений нужно вести лог действий // Ведение лога - $logger = $this->loadClass(FRAMEWORK_PATH . '/core/filter/actionlogger.php', $module); + $logger = $this->loadClass(FRAMEWORK_PATH . '/filter/actionlogger.php', $module, 'Filter_'); $logger->before = $this->loadSettings(Shortcut::getUrl('logger', $name)); // Управление доступом - $module->access = $this->loadClass(FRAMEWORK_PATH . '/core/filter/actionaccess.php', $logger); + $module->access = $this->loadClass(FRAMEWORK_PATH . '/filter/actionaccess.php', $logger, 'Filter_'); $module->access->access = $this->loadSettings(Shortcut::getUrl('access', $name)); $module->setUp(); - return $module->access->execute($request); + $this->modules[$name] = $module; + $result = $module->access->execute($request); + return $result; } return null; // throw new FileNotFoundException(); } @@ -80,13 +93,14 @@ class Controller_Front extends Controller $this->default = $name; } - private function getParameter(Collection $list) - { - return ($list->get($this->_param)) ? $list->get($this->_param): $this->default; - } - public function execute(HTTPRequest $request) { - return $this->loadModule($this->getParameter($request), $request); + $name = explode("_", $request->get($this->_param, $this->default)); + if (count($name) >= 2) { + $controller = $name[1]; + } else { + $controller = false; + } + return $this->loadModule($name[0], $request, $controller); } } diff --git a/core/controller/installer.php b/src/Controller/Installer.php similarity index 64% rename from core/controller/installer.php rename to src/Controller/Installer.php index a148839..dcc4562 100644 --- a/core/controller/installer.php +++ b/src/Controller/Installer.php @@ -1,10 +1,8 @@ _registry = $_registry; } - public function setUp($db, $installPath) + public function setUp($db_manager, $installPath) { - $this->db = $db; + $this->db_manager = $db_manager; $this->installPath = $installPath; } function getSetupFile($name) { - return Path::join(call_user_func($this->installPath, $name), "setup.php"); + $setup = Path::join(call_user_func($this->installPath, $name), "install.json"); + return $setup; + } + + function getUninstallFile($name){ + return Path::join(call_user_func($this->installPath, $name), "sql", "uninstall.json"); } // Проверка версии обновления @@ -40,22 +43,33 @@ class Installer function installSQL(array $sql, $version_new, $version_old, $name) { - require_once "core/setup.php"; + $result = []; + $json_installer = new Database_JsonInstall($this->db_manager); foreach ($sql as $version => $install) { if (version_compare($version, $version_new, "<=") && version_compare($version, $version_old, ">")) { - // this->installPath this->db $file = Path::join(call_user_func($this->installPath, $name), "sql", $install); - Setup::batchSQL($this->db, $file); + $json_installer->install($file,null); + $result[] = $version; } } + return $result; } + function uninstall($name){ + $uninstall = $this->getUninstallFile($name); + if (file_exists($uninstall)) { + $json_installer = new Database_JsonInstall($this->db_manager); + $json_installer->install($uninstall,null); + } + $this->_registry->removeKey($name); + $this->_registry->write(); + } // Устанавливает обновления если есть function doUpdates($name, $force = false) // Установка модуля { + $result = array(); $setup = $this->getSetupFile($name); if (file_exists($setup) && ($this->isChanged($name) || $force)) { - $registry = $this->_registry; $settings = new Settings($setup); $settings->read(); @@ -69,21 +83,29 @@ class Installer $version_old = "0.0"; $registry->writeKey(array($name), array()); } - if (version_compare($version_old, $settings->get('version'), "!=")) { $sql = $settings->get('sql'); if (is_array($sql)) { - $this->installSQL($sql, $version_new, $version_old, $name); + $res = $this->installSQL($sql, $version_new, $version_old, $name); + if($res){ + $result[]=$res; + } } } // Обновление версии меню + $registry->removeKey($name); $registry->writeKey(array($name), $settings->get('settings')); $registry->writeKey(array($name), array('version' => $version_new, 'time' => filemtime($setup))); $registry->write(); } + return $result; + } + + function install($dbinit_path,$dbfill_path=null){ + $json_installer = new Database_JsonInstall($this->db_manager); + $json_installer->install($dbinit_path,$dbfill_path); } } - diff --git a/src/Controller/Model.php b/src/Controller/Model.php new file mode 100644 index 0000000..4c1cbf9 --- /dev/null +++ b/src/Controller/Model.php @@ -0,0 +1,520 @@ +table->setHeader + */ + public $tableSchema = null; + public /*.array.*/$formSchema = array(); + + public $menu; + public $table; + + protected /*.string.*/$useModel; + protected /*.string.*/$itemModel; + + public function __construct() + { + parent::__construct(); + $this->menu = new Widgets_PageMenu(); + $this->table = new Widgets_ReactListTable(); + } + + /** + */ + function setUp() { + parent::setUp(); + $this->table->addMenuItem($this->aUrl('delete'), 'удалить', false, 'all', 'btn-danger', 'remove'); + } + + function saveParameters(HttpRequest $args, $list) { + foreach ($list as $item) { + $args->session()->set(array($this, $item), $args->get($item)); + } + } + + protected function getJSONList(/*.Model_Mapper.*/ $model, HttpRequest $request) { + $result = array(); + $this->saveParameters($request, array('size','page','desc', 'key')); + + $result['list'] = $model->findAll($request, $request->get('ref')); + $result['size'] = $model->getCount($request, $request->get('ref')); + return json_encode($result); + } + + protected function getCSV(Model_Mapper $model, HttpRequest $request, $title) { + $ref = $request->get('ref'); + + $list = $model->findAll($request, $request->get('ref')); + + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename='.$title.'.csv'); + + echo "\xEF\xBB\xBF"; //UTF-8 BOM. + + $output = fopen('php://output', 'w'); + if (is_resource($output)) { + foreach ($list as $row) { + fputcsv($output, (array)$row,';'); + } + } + } + + /** + * Удаление строк из таблицы + */ + public function actionDelete(HttpRequest $request) + { + $model = $this->getModel($this->useModel); + // Почему table_item ??? + $list = ($request->get('table_item')) ? $request->get('table_item'): $request->get('id'); + $model->deleteList($list); + +// return $this->getJSONList($model, $request); + return json_encode(array('result' => 'ok')); + } + + /** + * Ответ на запрос по поиску + */ + public function actionSearch(HttpRequest $request) + { + $model = $this->getModel($this->useModel); + $model->addFilter($model->requestToSQL($request, $this->formSchema)); + + return $this->getJSONList($model, $request); + } + + /** + * Список элементов + */ + public function actionList(HttpRequest $request) + { + $model = $this->getModel($this->useModel); + + if ($request->get('filter')) { + $data = new Collection(); + $data->import($request->get('filter')); + $model->addFilter($model->requestToSQL($data, $this->formSchema)); + } + return $this->getJSONList($model, $request); + } + + public function actionCSV(HttpRequest $request) + { + $model = $this->getModel($this->useModel); + $title = $request->get("title"); + if(!$title){ + $title = "noname"; + } + return $this->getCSV($model, $request, $title); + } + + private function setFormSchema() + { + $model = $this->getModel($this->useModel); + $ui = new Model_UIMapper($model); + + $this->formSchema = $ui->getFormSchema(); + } + + /** + * Сохранение формы + */ + function beforeSave(/*Model*/ $item, HttpRequest $request) + { + if (empty($this->formSchema)) { + $this->setFormSchema(); + } + // Сделать отображение Формы в обьект и обратно + foreach ($this->formSchema as $key => $conv) { + list($value, $type) = $conv; + $item->$value = call_user_func(array('Primitive', 'to_' . $type), $request->get($key)); // Здесь нужно преобразовывать тип значения + } + } + + /** + * Обновление формы + */ + function formUpdate(Form_Form $form, HttpRequest $request) { + $form->setValues($request); + } + + /** + * Загрузка формы + */ + function beforeLoad(/*.Model_Model.*/$item, Form_Form $form) + { + if (empty($this->formSchema)) { + $this->setFormSchema(); + } + // Вставка значений из данных в форму + // Отображение обьекта в поля формы + $form->fill($item, $this->formSchema); + } + + function beforeFirstLoad(Form_Form $form) + { + + } + + // Проверка ввода + protected function validate(Validator_Validator $validator, Collection $request) + { + } + + /** + * Действие для проверки формы + */ + public function actionValidate($request) + { + $validator = new Validator_Validator(); + $validator->addRuleList($this->schema); + + // Действия до проверки формы + $this->validate($validator, $request); // <--| + $validator->validate($request); // --| + // Проверка формы + if (!$validator->isValid()) { + return json_encode($validator->getErrorMsg()); + } + return json_encode(true); + } + + /** + * Инициализация формы + */ + protected function formSetup(Form_Form $form, $id = null, $ref = null) + { + if (empty($this->schema)) { + $model = $this->getModel($this->useModel); + $ui = new Model_UIMapper($model); + $schema = $ui->getEditSchema(); + + $form->addFieldList($schema); + } else { + $form->addFieldList($this->schema); + } + } + + /** + * Добавление + */ + public function actionAdd(HttpRequest $request) + { + // {{{ тоже может быть один ref или несколько + $ref = $request->get('ref'); + $this->addParameter('ref', $ref); // Добавляет параметр в url + /// }}} + + // Проверка + $validator = new Validator_Validator(); + $validator->addRuleList($this->schema); + + // Действия до проверки формы + $this->validate($validator, $request); // <--| + $validator->validate($request); // --| + // Проверка формы + if (!$validator->isValid()) { + return json_encode(array('result'=>'fail','errors'=>$validator->getErrorMsg())); + } + // Нужен тест для формы + $model = $this->getModel($this->useModel); + $className = $model->className; + $item = new $className(); + + // Сохраняем значение в базе данных + $item->id = $request->get('id'); + // Если таблица связана с другой таблицей + if ($request->get('ref') && $model->reference[1]) { + $ref_id = $model->reference[1]; + $item->$ref_id = $request->get('ref'); + } + + // Подготовка к сохранению + $this->beforeSave($item, $request); // Сюдаже и истрия переходов + // nextId ??? или выход или новая форма для создания новости + + $id = $model->saveDB($item, $request); + + // Для страницы со списком id -> идентификатор родительской таблицы !!?? +// $request->set('id', $request->get('ref')); + if ($request->get('apply')) { + $request->setAction('form'); + return (string) $this->forward('actionForm', $request); + } + //$request->setAction('index'); + $result = array('result'=>'ok'); + if($id){ + $result['action'] = forceUrl($this->nUrl('add', array('id' => $id, 'ref' => $request->get('ref')))); + } + return json_encode($result); + } + + /** + * Заголовок + */ + private function setTitlePath($ref) + { + if ($ref) { + $model = $this->getModel($this->useModel); + if (is_array($model->reference) && $model->reference[0]) { + $refmodel = $this->getModel($model->reference[0]); + try { + $parent = $refmodel->findById($ref); + $this->path->addTitle($parent->getTitle()); // Заголовок к подписям путей + } catch (Exception $e) { + // Не найден заголовок потому что неправильно определен родительский элемент + } + } + } + } + + /** + * Форма для редактирования + */ + public function actionForm(HttpRequest $request) + { + $this->getActionPath($request); + $ref = $request->get('ref'); + $this->addParameter('ref', $ref); // Добавляет параметр в url + $this->setTitlePath($ref); + + $model = $this->getModel($this->useModel); + $form = new Form_Form(); // Показываем форму + $form->header = 'Редактирование записи'; + $this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы + + $list = $request->get('table_item'); + $id = ($list[0]) ? $list[0] : $request->get('id'); + // + $tpl = $this->formPage($form, $request); + if ($id) { // Редактирование + $form->action = forceUrl($this->nUrl('add', array('id' => $id, 'page' => $this->getPageId($request)))); // action Свойство формы + $item = $model->findById($id); + // Загрузка формы + $this->beforeLoad($item, $form); + }else{//Создание нового элемента + $this->beforeFirstLoad($form); + } + return json_encode($tpl); + } + + /** + */ + function tableSetup(Widgets_ListTable $table, $id = null, $ref = null) + { + // FIXME: После замены везде $tableSchema -> table->setHeader удалить! + if ($this->tableSchema) { + $table->setHeader($this->tableSchema); + } else { + // Настройка таблицы отображения по схеме данных + $model = $this->getModel($this->useModel); + $ui = new Model_UIMapper($model); + $ui->hidden = $table->hidden; + + $schema = $ui->getTableSchema(); + $schema[0]['action'] = forceUrl($table->getFirstItem()); + + $table->setHeader($schema); + } + } + + /** + */ + public function actionDefault(HttpRequest $request) + { + $this->getActionPath($request, 'index'); + // Такое мета действие наверное можно вынести в отдельный класс + return $this->metaActionIndex($request, array($this, 'tableSetup'), $this->aUrl('list')); + } + + /** + * Страница по умолчанию + */ + public function metaActionIndex(HttpRequest $request, $setup, $list) + { + // может быть одно ref или несколько + // {{{ история переходов + $ref = null; + if ($request->get('ref')) { + $ref = $request->get('ref'); + } else if ($request->session()->get('ref')) { + $ref = $request->session()->get('ref'); + } + + $request->session()->set('ref', $ref); + $this->addParameter('ref', $ref); + // }}} + $this->setTitlePath($ref); + + $tpl = new stdClass(); + + // Помощники действий + $this->callHelpers($request); + // Таблица + if ($request->session()->get(strtolower(get_class($this)))) { + $session = $request->session()->get(strtolower(get_class($this))); + if (isset($session['view'])) { + $this->table->setView($session['view']); + } + $this->table->setData('state', array( + 'page' => $session['page'], + 'size' => $session['size'], + 'desc' => $session['desc'])); + + //$this->table->setData('sorter', $session['key']); + if (isset($session['desc'])) { + $this->table->setData('desc', $session['desc']); + } + } + + call_user_func($setup, $this->table, $request->get('id'), $ref);// --> Эквивалент formSetup + $this->table->setAction($list); + if (!$this->table->getData('module')) { + $this->table->setData('module', strtolower($this->useModel)); + } + $tpl->menu_path = $this->path->getItems(); + + $this->table->makeData(); + $tpl->table = array('data' => $this->table->data); + $tpl->menu = $this->menu->menu->getItems(); + $tpl->path = $this->path->getItems(); + + return json_encode($tpl); + } + + /** + */ + public function actionSetup(HttpRequest $request) { + $left = explode(",", $request->get('left')); + $right = explode(",", $request->get('right')); + + $request->session()->set(strtolower(get_class($this)), + array('view' => array('left' => $left, 'right' => $right), 'page' => 1, 'size' => 0, 'desc' => 'asc', 'key' => false)); + + return $this->forward('actionIndex', $request); + } + + /** + */ + protected function formPage($form, $request, $template = 'form') { + $view = new stdClass();//$this->getView($template); + $view->form = $form; + $form->action = forceUrl($this->nUrl('add', array('page' => $this->getPageId($request)))); // Действие для формы + + $view->path = $this->path->getItems(); + $view->back = $this->path->getPrev(); + return $view; + } + + function _getActionPath() { + return new Controller_State('index'); + } + + // Тоже убрать в метод Controller_Model + function getActionPath(HttpRequest $request, $action = null) { + $this->_getActionPath()->getPath($this, ($action) ? $action : $request->getAction()); + } + + + function parse_params($expression) { + $expression = htmlspecialchars_decode($expression); + $offset = strpos($expression, '?'); + $url = parse_url($expression); + + $arguments = array(); + if ($offset === false) { + $path = $expression; + } else if (is_int($offset)) { + $path = substr($expression, 0, $offset); + $query = substr($expression, $offset+1); + parse_str($query, $arguments); + } + return $arguments; + } + + public function actionFormPage(HttpRequest $request) { + //$tpl = $this->getView('formpage', 'View_Top'); + + $view = $this->getView('formpage', 'View_Top'); + + $params = $this->parse_params($request->get('params')); + + +// $model = $this->getModel($this->useModel); + $form = new Form_Form(); // Показываем форму + $form->header = 'Редактирование записи'; + $this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы + /* + $ui = new Model_UIMapper($model); + $schema = $ui->getEditSchema(); + $form->addFieldList($schema); + */ + + $list = $request->get('table_item'); + $id = ($list[0]) ? $list[0] : $request->get('id'); + +// $tpl = $this->formPage($form, $request); + + $view->setView('form', $form); + $view->action = forceUrl($this->nUrl('addpage', array('ref' => $params['id']))); // Действие для формы + +// $view->menu_path = $this->path->getItems(); + $view->back = ''; + return $view; + +// return $tpl; + } + + /* Для поддержки редактрования на сайте */ + public function actionAddPage(HttpRequest $request) + { + // {{{ тоже может быть один ref или несколько + $ref = $request->get('ref'); + $this->addParameter('ref', $ref); // Добавляет параметр в url + /// }}} + $validator = new Validator_Validator(); + $validator->addRuleList($this->schema); + + // Действия до проверки формы + $this->validate($validator, $request); // <--| + $validator->validate($request); // --| + // Проверка формы + if (!$validator->isValid()) { + return $validator; + } + + // Нужен тест для формы + $model = $this->getModel($this->useModel); + $className = $model->className; + $item = new $className(); + + // Сохраняем значение в базе данных + $item->id = $request->get('id'); + // Если таблица связана с другой таблицей + if ($request->get('ref') && $model->reference[1]) { + $ref_id = $model->reference[1]; + $item->$ref_id = $request->get('ref'); + } + + // Подготовка к сохранению + $this->beforeSave($item, $request); // Сюдаже и истрия переходов + $model->saveDB($item, $request); + + return null; + } +} diff --git a/src/Controller/Request.php b/src/Controller/Request.php new file mode 100644 index 0000000..01822e1 --- /dev/null +++ b/src/Controller/Request.php @@ -0,0 +1,16 @@ +r = $request; + $this->id = $id; + } + + function get($name) { + $v = $this->r->get($name); + if ($id && is_array($v)) { + return isset($v[$id]) ? $v[$id] : $def; + } + return $v; + } +} diff --git a/src/Controller/Service.php b/src/Controller/Service.php new file mode 100644 index 0000000..87aa3bd --- /dev/null +++ b/src/Controller/Service.php @@ -0,0 +1,64 @@ +getInstance + public $template; + public $templatePath; + public $COMPONENTS_WEB; + + public function getTemplatePath($name) + { + return Path::join($this->viewPath[0], 'templates', 'modern', $name); + } + + public function getTemplateWebPath() + { + return Path::join($this->webPath[0], strtolower(get_class($this)), 'templates', 'modern'); + } + + /** + * @param $name Имя модели + */ + private function getModelPath($name) + { + return Path::join (CMS_PATH, "model", $name . ".php"); + } + + /** + * Создает модель + * @param string $name + * @return model + */ + public function getModel($name) + { + require_once 'mapper/mapper.php'; + + require_once ($this->getModelPath ($name)); + $modelName = $name . "Mapper"; + $model = new $modelName (); + $model->db = $this->db; + return $model; + } + + public function options($key, $val, $res) { + $result = array(); + while($res->next()) { + $result[] = array('value' => $res->getInt($key), 'name' => $res->getString($val)); + } + return $result; + } + + public function optionsPair($list, $selected = false) { + $result = array(); + foreach ($list as $key => $value) { + $result [] = array('value' => $key, 'name' => $value, 'selected' => $key == $selected); + } + return $result; + } +} + diff --git a/core/controller/state.php b/src/Controller/State.php similarity index 84% rename from core/controller/state.php rename to src/Controller/State.php index 3079c70..aafff35 100644 --- a/core/controller/state.php +++ b/src/Controller/State.php @@ -1,6 +1,6 @@ states [$state->getAction()] = $state; return $this; @@ -49,7 +49,7 @@ class State return false; } - function makeTitle($module) + function makeTitle(Controller_Action $module) { foreach ($this->titles as $item) { $module->path->addMenuItem($module->nUrl($this->action, $item[1]), $item[0]); @@ -68,12 +68,3 @@ class State } } } - - -/* -$path = State::make('index') - ->addState(State::make('form')) - ->addState(State::make('view')); - -$path->getPath(0, 'form'); -*/ diff --git a/src/Database.php b/src/Database.php new file mode 100644 index 0000000..c4cd264 --- /dev/null +++ b/src/Database.php @@ -0,0 +1,180 @@ + +require_once "database/pdostatement.php"; +/** + * Класс оболочка для PDO для замены Creole + */ +class Database extends PDO +{ + + public $dsn; + public function __construct($dsn, $username = null, $password = null) + { + parent::__construct($dsn, $username, $password); + $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Database_PDOStatement', array())); + } + + public function getDSN() + { + return $this->dsn; + } + public function isPostgres(){ + return ($this->dsn["phptype"] == "pgsql"); + } + /** + * Создает соединение с базой данных + */ + static function getConnection(array $dsn) + { + + if ($dsn['phptype'] == 'pgsql' || $dsn['phptype'] == 'mysql') { + $port = (isset($dsn['port'])) ? "port={$dsn['port']};" : ""; + /*.Database.*/$connection = new static("{$dsn['phptype']}:host={$dsn['hostspec']}; $port dbname={$dsn['database']}", $dsn['username'], $dsn['password']); + if ($dsn['phptype'] == 'pgsql') { + $connection->query('SET client_encoding="UTF-8"'); + } + } + if ($dsn['phptype'] == 'sqlite') { + /*.Database.*/$connection = new static("{$dsn['phptype']}:{$dsn['database']}"); + $connection->setAttribute(PDO::ATTR_TIMEOUT, 5); + $mode = defined('SQLITE_JOURNAL_MODE') ? SQLITE_JOURNAL_MODE : 'WAL'; + $connection->query("PRAGMA journal_mode=$mode"); + + if(!function_exists('sqliteLower')){ + function sqliteLower($str) { + return mb_strtolower($str, 'UTF-8'); + } + $connection->sqliteCreateFunction('LOWER', 'sqliteLower', 1); + } + } + $connection->dsn = $dsn; + return $connection; + } + + public function executeQuery($query, $values=null) + { + /*.Database_PDOStatement.*/$stmt = $this->prepare($query); + + $stmt->execute($values); + $stmt->cache = $stmt->fetchAll(PDO::FETCH_ASSOC); + return $stmt; + } + + public function prepareStatement($query) + { + return new Database_Statement($query, $this); + } + + // Для совместимости со старым представлением баз данных CIS + /** + * Извлекает из базы все элементы по запросу + */ + public function fetchAllArray($query,$values=null) + { + /*.Database_PDOStatement.*/$sth = $this->prepare($query); + $prep = $this->prepareValues($values); + $sth->execute($prep); + return $sth->fetchAll(PDO::FETCH_ASSOC); + } + + /** + * Извлекает из базы первый элемент по запросу + */ + public function fetchOneArray($query,$values=null) + { + /*.Database_PDOStatement.*/$sth = $this->prepare($query); + $prep = $this->prepareValues($values); + $sth->execute($prep); + return $sth->fetch(PDO::FETCH_ASSOC); + } + + private static function assignQuote($x, $y) + { + return $x . "=" . $this->quote($y); + } + + private function prepareValues($values) + { + if (!$values) { + return null; + } + $pg = $this->isPostgres(); + $prep = array(); + foreach ($values as $key => $value) { + $result = null; + if(is_bool($value)) { + if ($pg) { + $result = $value ? 'true' : 'false'; + } else { + $result = $value ? 1 : 0; + } + } else { + $result = $value; + } + $prep[":" . $key] = $result; + } + return $prep; + } + /** + * Создает INSERT запрос + */ + function insertQuery($table, array $values, $return_id = false, $index = null) + { + $prep = $this->prepareValues($values); + + $sql = "INSERT INTO $table (" . implode(",", array_keys($values)) + . ") VALUES (" . implode(",", array_keys($prep)). ")"; + + if($return_id){ + if ($this->isPostgres()){ + $sql = $sql." RETURNING $index"; + } + } + $stmt = $this->prepare($sql); + $stmt->setFetchMode(PDO::FETCH_ASSOC); + $stmt->execute($prep); + $result = $stmt->fetch(); + if ($return_id) { + if ($this->isPostgres()) { + return $result[$index]; + } else { + $result = $this->fetchOneArray("SELECT $index AS lastid FROM $table WHERE OID = last_insert_rowid()"); + return $result['lastid']; + } + } + } + + /** + * Создает UPDATE запрос + */ + function updateQuery($table, array $values, $cond) + { + $prep = $this->prepareValues($values); + $sql = "UPDATE $table SET " . implode(",", + array_map(function($k,$v){return $k."=".$v;}, array_keys($values), array_keys($prep))) . " WHERE $cond"; + + $stmt = $this->prepare($sql); + $stmt->setFetchMode(PDO::FETCH_ASSOC); + $stmt->execute($prep); + } + + function getIdGenerator() { + return new Database_IdGenerator($this); + } + + /** + * Замечание: Только для Postgres SQL + * @param string $seq Имя последовательности для ключа таблицы + * @return int Идентефикатор следующей записи + */ + function getNextId($seq) { + $result = $this->fetchOneArray("SELECT nextval('$seq')"); + return $result['nextval']; + } + + function close() + { + return null; + } +} diff --git a/src/Database/IdGenerator.php b/src/Database/IdGenerator.php new file mode 100644 index 0000000..045ec86 --- /dev/null +++ b/src/Database/IdGenerator.php @@ -0,0 +1,26 @@ +db = $db; + } + + function isBeforeInsert() { + return false; + } + + function isAfterInsert() { + return true; + } + + function getId($seq) { + if ($this->db->isPostgres()) { + $result = $this->db->fetchOneArray("SELECT nextval('$seq') AS nextval"); + } else { + $result = $this->db->fetchOneArray("SELECT last_insert_rowid() AS nextval"); + } + return intval($result['nextval']); + } +} diff --git a/src/Database/JsonInstall.php b/src/Database/JsonInstall.php new file mode 100644 index 0000000..ee62cf3 --- /dev/null +++ b/src/Database/JsonInstall.php @@ -0,0 +1,143 @@ +db_manager = $db_manager; + } + + function install($dbinit_path, $dbfill_path = null) { + $dbinit_file = file_get_contents($dbinit_path); + if (is_string($dbinit_file)) { + $initActions = json_decode($dbinit_file, true); + if (!$initActions) { + echo "Invalid dbinit.json ".$dbinit_file; + return 0; + } + } else { + echo "No dbinit.json"; + return 0; + } + + $this->initDataBase($initActions, $dbinit_path); + if ($dbfill_path) { + $this->fillDataBase($dbfill_path); + } + $this->makeConstraints($initActions); + } + + function missingTables($tables) { + $actual_tables = $this->db_manager->GetAllTableNames(); + $missingTables = []; + foreach ($tables as $table) { + if (!in_array($table, $actual_tables)) + $missingTables[] = $table; + } + return $missingTables; + } + + //Создать таблицы + function initDataBase(/*.array.*/$initActions, $dbinit_path) { + $pg = $this->db_manager->db->isPostgres(); + if (!$pg) { + $refs = []; + //В sqlite нет alter reference. Референсы надо создавать при создании таблицы. + foreach ($initActions as $action) { + if ($action["type"] == "alterReference") { + if (!isset($refs[$action["table"]])) + $refs[$action["table"]] = []; + $refs[$action["table"]][]=$action;//добавить к списку референсов для таблицы + } + } + } + + foreach ($initActions as $action) { + if (!$pg) { + if ($action["type"] == "createTable") { + $table_name = $action["table_name"]; + if (isset($refs[$table_name])) { + foreach ($refs[$table_name] as $value) { + $action['fields'][$value['column']]['references'] = + $value['refTable']."(".$value['refColumn'].")"; + } + } + + } + } + if ($action["type"] != "alterReference") { + $this->db_manager->ExecuteAction($action, $dbinit_path); + } + } + + //Запомнить все колонки serial + $this->serialColumns = []; + if ($pg) { + foreach ($initActions as $action) { + if ($action["type"] == "createTable") { + foreach ($action["fields"] as $name => $field) { + if ($field["type"]=="serial") { + $this->serialColumns[] = [ + "table"=>$action["table_name"], + "column"=>$name + ]; + } + } + } + } + } + } + + //Заполнить данными + function fillDataBase($dbfill_file_path) { + $dbfill_file = file_get_contents($dbfill_file_path); + if (is_string($dbfill_file)) { + $actions = json_decode($dbfill_file,true); + if ($actions) { + + //Проверка что упоминаемые в списке действий таблицы уже есть в базе + $affected_tables = []; + foreach ($actions as $action) { + if ($action["table_name"]) { + $affected_tables[$action["table_name"]] = 1; + } + } + + $missing = $this->missingTables(array_keys($affected_tables)); + if (!empty($missing)) { + echo "dbfill error. Missing tables: ".implode(" ", $missing); + return; + } + + //Выполнение действий + foreach ($actions as $action) { + $this->db_manager->ExecuteAction($action, $dbfill_file_path); + } + } else { + echo "Invalid dbfill.json"; + } + } else { + echo "No dbfill.json"; + } + } + + //Обновить ключи serial и создать ограничения + function makeConstraints($initActions) { + $pg = $this->db_manager->db->isPostgres(); + if ($pg) { + foreach ($this->serialColumns as $serialColumn) { + $this->db_manager->UpdateSerial($serialColumn["table"], $serialColumn["column"]); + } + + + foreach ($initActions as $action) { + if ($action["type"] == "alterReference") { + $this->db_manager->ExecuteAction($action); + } + } + } + } + +} \ No newline at end of file diff --git a/src/Database/Manager.php b/src/Database/Manager.php new file mode 100644 index 0000000..11b8dbc --- /dev/null +++ b/src/Database/Manager.php @@ -0,0 +1,211 @@ +db = $db; + } + + public function ExecuteAction(/*.array.*/$action, $db_file = "") { + switch($action["type"]) { + case "dropTable": + $this->DropTableQuery($action["table_name"], true); + break; + case "createTable": + $constraints = isset($action["constraints"]) ? $action["constraints"] : NULL; + $this->CreateTableQuery($action["table_name"], $action["fields"], $constraints); + break; + case "addColumn": + $this->AddColumn($action["table_name"], $action["column_name"], $action["field"]); + break; + case "insert": + $this->db->insertQuery($action["table_name"], $action["values"]); + break; + case "alterReference": + $this->AlterReference($action["table"], $action["column"], $action["refTable"], $action["refColumn"]); + break; + case "renameColumn": + $this->RenameColumn($action["table"], $action["old_name"], $action["new_name"]); + break; + case "executeFile": + if ($this->db->isPostgres() && isset($action["pgsql"])) { + $file = $action["pgsql"]; + } else { + $file = $action["source"]; + } + + $stmtList = Tools_SQLStatementExtractor::extractFile(Path::join(dirname($db_file), $file)); + foreach($stmtList as $stmt) { + $this->db->executeQuery($stmt); + } + + break; + default: + throw new Exception("unknown action ". $action["type"] . PHP_EOL); + } + } + + public function DropTableQuery($table, $cascade=false) { + $statement = "DROP TABLE IF EXISTS ".$table; + if ($this->db->isPostgres()&&$cascade) { + $statement = $statement." CASCADE"; + } + $this->db->query($statement); + } + + public function AlterReference($table,$column,$refTable,$refColumn) { + $this->db->query("ALTER TABLE ".$table." ADD CONSTRAINT ".$table."_".$column."fk"." FOREIGN KEY (".$column.") REFERENCES ".$refTable." (".$refColumn.")"); + } + + //Извлечение информации о полях таблицы + public function TableInfo($table) { + $pg = $this->db->isPostgres(); + if ($pg) { + throw new Exception("Not implemented for postgres"); + } else { + $results = $this->db->fetchAllArray("PRAGMA table_info(".$table.");"); + if (empty($results)) { + return null; + } + $fields = []; + foreach ($results as $result) { + $fields[$result["name"]] = [ + "type"=> $result["type"], + "not_null"=> boolval($result["notnull"]), + "constraint"=> ((boolean) $result["pk"]) ? "PRIMARY KEY" : null + ]; + } + return $fields; + } + } + + public function RenameColumn($table, $old_name, $new_name) { + $pg = $this->db->isPostgres(); + if ($pg) { + $this->db->query("ALTER TABLE ".$table." RENAME COLUMN ".$old_name." TO ".$new_name); + } else { + $tmp_table = "tmp_" . $table; + $this->DropTableQuery($tmp_table); + $table_info = $this->TableInfo($table); + + if (isset($table_info[$new_name])) { + return; + } + + /*.array.*/$data = $this->DumpTable($table); + + $this->db->query("ALTER TABLE ".$table." RENAME TO ".$tmp_table.";"); + $table_info[$new_name] = $table_info[$old_name]; + unset($table_info[$old_name]); + $this->CreateTableQuery($table,$table_info,null); + + foreach ($data as $row) { + $values = $row['values']; + $values[$new_name] = $values[$old_name]; + unset($values[$old_name]); + $this->db->insertQuery($table, $values); + } + $this->DropTableQuery($tmp_table); + } + } + + //Обновление ключа serial после ручной вставки + public function UpdateSerial($table,$column) { + $this->db->query("SELECT setval(pg_get_serial_sequence('".$table."', '".$column."'), coalesce(max(".$column."),0) + 1, false) FROM ".$table); + } + + public function Column_Definition($name,$data,$pg){ + $constraint = isset($data['constraint'])?" ".$data['constraint']:""; + $references = ""; + if (isset($data['references'])) { + $references = " REFERENCES ".$data['references']; + } + if (isset($data["not_null"])&&$data["not_null"]) + $constraint .=" NOT NULL"; + $type = $data['type']; + if (!$pg) { + if (strtolower($type)=="serial") + $type = "integer"; + //if (strtolower($type)=="boolean") + // $type = "integer"; + } + return $name." ".$type.$references.$constraint; + } + + public function AddColumn($table_name,$column_name,$field){ + $pg = $this->db->isPostgres(); + $q = "ALTER TABLE ".$table_name." ADD COLUMN ". + $this->Column_Definition($column_name, $field, $pg); + $this->db->query($q); + } + + //CreateTableQuery('users',['id'=>['type'=>'integer','constraint'=>'PRIMARY KEY']]) + public function CreateTableQuery($table, $fields, $constraints) { + $pg = $this->db->isPostgres(); + if ($constraints) { + $constraints = ", " . $constraints; + } + + $statement = "CREATE TABLE $table (" . implode(",", + array_map(function($name,$data) use ($pg) { + return $this->Column_Definition($name,$data,$pg); + }, array_keys($fields), array_values($fields)) + ) . " " . $constraints . ")"; + $this->db->query($statement); + } + + public function DumpTable($table_name) { + $pg = $this->db->isPostgres(); + + /*.array.*/$result = array(); + /*.array.*/$data = $this->db->fetchAllArray("SELECT * FROM ".$table_name.";"); + + if (!$pg) { + $table_fields = $this->TableInfo($table_name); + foreach ($table_fields as $name => $value) { + $type = strtolower($value['type']); + if ($type == "boolean") { + foreach ($data as &$row) { + /*.array.*/$row = $row; + if (isset($row[$name])) { + $row[$name] = boolval($row[$name]); + } + } + } + } + } + foreach ($data as $r) { + $result[] = array( + "type" => "insert", + "table_name" => $table_name, + "values" => $r + ); + } + return $result; + } + + public function GetAllTableNames() { + $result = []; + if ($this->db->isPostgres()) { + $query = "SELECT table_name as name FROM information_schema.tables WHERE table_schema='public'"; + } else { + $query = "SELECT * FROM sqlite_master WHERE type='table'"; + } + $tables = $this->db->fetchAllArray($query); + foreach ($tables as $table) { + $result[] = $table['name']; + } + return $result; + } + + public function DumpInserts() { + $table_names = $this->GetAllTableNames(); + $result = array(); + foreach ($table_names as $table_name) { + $result = array_merge($result, $this->DumpTable($table_name)); + } + return $result; + } +} \ No newline at end of file diff --git a/src/Database/PDOStatement.php b/src/Database/PDOStatement.php new file mode 100644 index 0000000..4df5db7 --- /dev/null +++ b/src/Database/PDOStatement.php @@ -0,0 +1,97 @@ +cursorPos = 0; + } + + public function seek($rownum) { + if ($rownum < 0) { + return false; + } + + // PostgreSQL rows start w/ 0, but this works, because we are + // looking to move the position _before_ the next desired position + $this->cursorPos = $rownum; + return true; + } + + function valid() { + return true; + } + + + public function first() { + if($this->cursorPos !== 0) { $this->seek(0); } + return $this->next(); + } + + function next() { + if ($this->getRecordCount() > $this->cursorPos) { + if (!isset($this->cache[$this->cursorPos])) { + $this->cache[$this->cursorPos] = $this->fetch(PDO::FETCH_ASSOC); + } + $this->fields = $this->cache[$this->cursorPos]; + + $this->cursorPos++; + return true; + } else { + $this->fields = null; + return false; + } + } + + function key() { + return $this->cursorPos; + } + + function current() { + return $this->cache[$this->cursorPos]; + } + + function getRow() { + return $this->fields; + } + + function getInt($name) { + return intval($this->fields[$name]); + } + + function getBlob($name) { + return $this->fields[$name]; + } + + function getString($name) { + return $this->fields[$name]; + } + + function getBoolean($name) { + return (bool)$this->fields[$name]; + } + + function get($name) { + return $this->fields[$name]; + } + + function getArray($name) { + return strToArray($this->fields[$name]); + } + + function getRecordCount() { + return count($this->cache); + } +} diff --git a/src/Database/Statement.php b/src/Database/Statement.php new file mode 100644 index 0000000..80b77da --- /dev/null +++ b/src/Database/Statement.php @@ -0,0 +1,61 @@ +query = $query; + $this->conn = $conn; + } + + function setInt($n, $value) + { + $this->binds [] = array($n, $value, PDO::PARAM_INT); + } + + function setString($n, $value) + { + $this->binds [] = array($n, $value, PDO::PARAM_STR); + } + + function setBlob($n, $value) + { + $this->binds [] = array($n, $value, PDO::PARAM_LOB); + } + + function setLimit($limit) + { + $this->limit = $limit; + } + + function setOffset($offset) + { + $this->offset = $offset; + } + + function executeQuery() + { + if ($this->limit) { + $this->query .= " LIMIT {$this->limit} OFFSET {$this->offset}"; + } + /*.Database_PDOStatement.*/$stmt = $this->conn->prepare($this->query); + foreach ($this->binds as $bind) { + list($n, $value, $type) = $bind; + $stmt->bindValue($n, $value, (int) $type); + } + + $stmt->execute(); + $stmt->cache = $stmt->fetchAll(PDO::FETCH_ASSOC); + + return $stmt; + } +} diff --git a/src/Database/StatementIterator.php b/src/Database/StatementIterator.php new file mode 100644 index 0000000..cc2cc05 --- /dev/null +++ b/src/Database/StatementIterator.php @@ -0,0 +1,46 @@ +result = $rs; + $this->row_count = $rs->getRecordCount(); + } + + function rewind() { + $this->pos = 0; + } + + function valid() { + return ($this->pos < $this->row_count); + } + + function key() { + return $this->pos; + } + + function current() { + if (!isset($this->result->cache[$this->pos])) { + $this->result->cache[$this->pos] = $this->result->fetch(PDO::FETCH_ASSOC); + } + return $this->result->cache[$this->pos]; + } + + function next() { + $this->pos++; + } + + function seek($index) { + $this->pos = $index; + } + + function count() { + return $this->row_count; + } +} diff --git a/src/Excel/DataTime.php b/src/Excel/DataTime.php new file mode 100644 index 0000000..0536cbd --- /dev/null +++ b/src/Excel/DataTime.php @@ -0,0 +1,16 @@ +value = intval($value); + } + + function getString() + { + return date('Y-m-d\TH:i:s.u', $this->value); + } +} diff --git a/src/Excel/Document.php b/src/Excel/Document.php new file mode 100644 index 0000000..e46ff31 --- /dev/null +++ b/src/Excel/Document.php @@ -0,0 +1,100 @@ +table [] = $table; + } + + /** + * Добавление стиля к документу + * @param $name string Имя стиля + * @param $values array Параметры стиля + * @param $type Тип стиля + */ + function setStyle ($name, array $values, $type = 'Interior') + { + if(!isset($this->styles[$name])) { + $this->styles[$name] = array(); + } + $this->styles[$name][$type] = $values; + } + + /** + * Генерация стилей + */ + private function createStyles (XMLWriter $doc) { + $doc->startElement('Styles'); + foreach ($this->styles as $name => $sn) { + $doc->startElement('Style'); + $doc->writeAttribute('ss:ID', $name); + foreach ($sn as $type => $s) { + // Стиль Borders - составной + if ($type == 'Borders') { + $doc->startElement('Borders'); + foreach ($s as $border) { + /*.array.*/$border = $border; + $doc->startElement('Border'); + foreach ($border as $key => $value) { + $doc->writeAttribute('ss:' . $key, $value); + } + $doc->endElement(); + } + $doc->endElement(); + } else { + $doc->startElement($type); + foreach ($s as $key => $value) { + $doc->writeAttribute('ss:' . $key, $value); + } + $doc->endElement(); + } + } + $doc->endElement(); + } + $doc->endElement(); + } + + /** + * Преобразует переводы строки в спец символы + */ + function clean ($s) { + assert(is_string($s)); + + return strtr($s, array ("\n" => " ")); + } + + /** + * Сохраняет таблицу в формате Office 2003 XML + * http://en.wikipedia.org/wiki/Microsoft_Office_XML_formats + */ + function save($filename) + { + $doc = new XMLWriter(); + $doc->openURI($filename); + $doc->setIndent(false); + $doc->startDocument('1.0','utf-8'); + $doc->startElement('Workbook'); + $doc->writeAttribute('xmlns', self::$ns); + $doc->writeAttribute('xmlns:ss', self::$ns); + + $this->createStyles($doc); + + foreach ($this->table as $table) { + if ($table instanceof Excel_Table) { + $table->createTable($doc); + } else { + $table_data = call_user_func($table); + $table_data->createTable($doc); + unset($table_data); + } + } + $doc->endElement(); + } +} + diff --git a/src/Excel/Number.php b/src/Excel/Number.php new file mode 100644 index 0000000..66dd6b6 --- /dev/null +++ b/src/Excel/Number.php @@ -0,0 +1,17 @@ +value = intval($value); + } + + function getString() + { + return $this->value; + } +} + diff --git a/core/tools/exceltable.php b/src/Excel/Table.php similarity index 61% rename from core/tools/exceltable.php rename to src/Excel/Table.php index 0816ee8..162c823 100644 --- a/core/tools/exceltable.php +++ b/src/Excel/Table.php @@ -1,35 +1,5 @@ value = $value; - } - - function getString() - { - return $this->value; - } -} - -class Excel_DateTime -{ - public $value; - - function __construct($value) - { - $this->value = intval($value); - } - - function getString() - { - return date('Y-m-d\TH:i:s.u', $this->value); - } -} - /** * Клетка таблицы */ @@ -68,15 +38,15 @@ class TableRow /** * Таблица */ -class ExcelTable +class Excel_Table { - static $index; + static $index; private $name; private $style; - protected $rows = array(); + protected $rows = array(); - protected $splitVertical = false; - protected $splitHorizontal = false; + protected $_splitVertical = false; + protected $_splitHorizontal = false; function __construct() { @@ -94,7 +64,8 @@ class ExcelTable if(! isset($this->rows[$x])) { $this->rows[$x] = new TableRow(); } - $this->rows[$x]->setCell($y, $value); + /*.TableRow.*/$row = $this->rows[$x]; + $row->setCell($y, $value); } /** @@ -142,12 +113,13 @@ class ExcelTable * @param $cell Номер столбца * @param $merge Количество клеток для обьединения */ - function setCellMerge ($row, $cell, $merge) + function setCellMerge($x, $cell, $merge) { - assert(is_numeric($row) && $row > 0); + assert(is_numeric($x) && $x > 0); assert(is_numeric($cell) && $cell > 0); - $this->rows[$row]->cells[$cell]->merge = $merge; + /*.TableRow.*/$row = $this->rows[$x]; + $row->cells[$cell]->merge = $merge; } /** @@ -181,7 +153,8 @@ class ExcelTable */ function getRows() { - return max(array_keys($this->rows)); + /*.array.*/$keys = array_keys($this->rows); + return max($keys); } /** @@ -189,27 +162,26 @@ class ExcelTable * * @return int */ - function getRowCells($row) + function getRowCells(TableRow $row) { - return max(array_keys($row->cells)); + /*.array.*/$keys = array_keys($row->cells); + return max($keys); } /** * Разделяет таблицу на две части по вертикали * @param $n integer Количество столбцов слева */ - function splitVertical($n) - { - $this->splitVertical = $n; + function splitVertical($n) { + $this->_splitVertical = $n; } /** * Разделяет таблицу на две части по горизонтали * @param $n integer Количество столбцов сверху */ - function splitHorizontal($n) - { - $this->splitHorizontal = $n; + function splitHorizontal($n) { + $this->_splitHorizontal = $n; } @@ -218,8 +190,7 @@ class ExcelTable * * @return int */ - function getColumns() - { + function getColumns() { return max(array_map(array($this, 'getRowCells'), $this->rows)); } @@ -231,7 +202,7 @@ class ExcelTable /** * Генерация клетки таблицы (Переработать) */ - function createCell ($ncell, XMLWriter $doc, $j, $value, $setIndex) { + function createCell (TableCell $ncell, XMLWriter $doc, $j, /*.any.*/$value, $setIndex) { $doc->startElement("Cell"); if ($ncell->style) { @@ -291,7 +262,7 @@ class ExcelTable $doc->writeAttribute('ss:Height', $this->rows[$i]->height); } - $nrow = $this->rows[$i]; + /*.TableRow.*/$nrow = $this->rows[$i]; // Флаг индикатор подстановки номера столбца $setIndex = false; for ($j = 1; $j <= $columns; $j++) { @@ -321,117 +292,20 @@ class ExcelTable $doc->writeAttribute('xmlns', 'urn:schemas-microsoft-com:office:excel'); $doc->writeElement('FrozenNoSplit'); - if ($this->splitVertical) { - $doc->writeElement('SplitVertical', $this->splitVertical); - $doc->writeElement('LeftColumnRightPane', $this->splitVertical); + if ($this->_splitVertical) { + $doc->writeElement('SplitVertical', $this->_splitVertical); + $doc->writeElement('LeftColumnRightPane', $this->_splitVertical); } - if ($this->splitHorizontal) { - $doc->writeElement('SplitHorizontal', $this->splitHorizontal); - $doc->writeElement('TopRowBottomPane', $this->splitHorizontal); + if ($this->_splitHorizontal) { + $doc->writeElement('SplitHorizontal', $this->_splitHorizontal); + $doc->writeElement('TopRowBottomPane', $this->_splitHorizontal); } - if ($this->splitHorizontal && $this->splitVertical) { + if ($this->_splitHorizontal && $this->_splitVertical) { $doc->writeElement('ActivePane', 0); - } else if($this->splitHorizontal) { + } else if($this->_splitHorizontal) { $doc->writeElement('ActivePane', 2); } $doc->endElement(); } } -/** - * Документ - */ -class ExcelDocument { - static $ns = "urn:schemas-microsoft-com:office:spreadsheet"; - private $table = array (); - protected $styles = array(); - - function addTable($table) { - $this->table [] = $table; - } - - /** - * Добавление стиля к документу - * @param $name string Имя стиля - * @param $values array Параметры стиля - * @param $type Тип стиля - */ - function setStyle ($name, array $values, $type = 'Interior') - { - if(!isset($this->styles[$name])) { - $this->styles[$name] = array(); - } - $this->styles[$name][$type] = $values; - } - - /** - * Генерация стилей - */ - private function createStyles (XMLWriter $doc) { - $doc->startElement('Styles'); - foreach ($this->styles as $name => $sn) { - $doc->startElement('Style'); - $doc->writeAttribute('ss:ID', $name); - foreach ($sn as $type => $s) { - // Стиль Borders - составной - if ($type == 'Borders') { - $doc->startElement('Borders'); - foreach ($s as $border) { - $doc->startElement('Border'); - foreach ($border as $key => $value) { - $doc->writeAttribute('ss:' . $key, $value); - } - $doc->endElement(); - } - $doc->endElement(); - } else { - $doc->startElement($type); - foreach ($s as $key => $value) { - $doc->writeAttribute('ss:' . $key, $value); - } - $doc->endElement(); - } - } - $doc->endElement(); - } - $doc->endElement(); - } - - /** - * Преобразует переводы строки в спец символы - */ - function clean ($s) { - assert(is_string($s)); - - return strtr($s, array ("\n" => ' ')); - } - - /** - * Сохраняет таблицу в формате Office 2003 XML - * http://en.wikipedia.org/wiki/Microsoft_Office_XML_formats - */ - function save($filename) - { - $doc = new xmlWriter(); - $doc->openURI($filename); - $doc->setIndent(false); - $doc->startDocument('1.0','utf-8'); - $doc->startElement('Workbook'); - $doc->writeAttribute('xmlns', self::$ns); - $doc->writeAttribute('xmlns:ss', self::$ns); - - $this->createStyles($doc); - - foreach ($this->table as $table) { - if ($table instanceof ExcelTable) { - $table->createTable($doc); - } else { - $table_data = call_user_func($table); - $table_data->createTable($doc); - unset($table_data); - } - } - $doc->endElement(); - } -} - diff --git a/core/filter/actionaccess.php b/src/Filter/ActionAccess.php similarity index 72% rename from core/filter/actionaccess.php rename to src/Filter/ActionAccess.php index a44721b..dc39ba0 100644 --- a/core/filter/actionaccess.php +++ b/src/Filter/ActionAccess.php @@ -3,12 +3,12 @@ /** * Фильтр действий */ -class ActionAccess +class Filter_ActionAccess { public $access = array(); + public $processor; - function __construct($processor) - { + function __construct(/*.Filter_Filter.*/$processor) { $this->processor = $processor; } @@ -17,14 +17,12 @@ class ActionAccess * !! Реализация класса проверки действий не должна быть внутри Контроллера!!! * Информация о доступе может быть в файле, базе данных и т.д. */ - function checkAction($action) - { + function checkAction($action) { // Импликация !! http://ru.wikipedia.org/wiki/Импликация - return (!isset($this->access[$action]) || in_array(UserAccess::$access, $this->access[$action])); + return (!isset($this->access[$action]) || in_array(Filter_UserAccess::$access, $this->access[$action])); } - function execute(HTTPRequest $request) - { + function execute(HttpRequest $request) { $action = $request->getAction(); if(! $this->checkAction($action)) { $request->set('action', 'index'); diff --git a/core/filter/actionlogger.php b/src/Filter/ActionLogger.php similarity index 60% rename from core/filter/actionlogger.php rename to src/Filter/ActionLogger.php index fce3ef5..a71d5f5 100644 --- a/core/filter/actionlogger.php +++ b/src/Filter/ActionLogger.php @@ -1,25 +1,21 @@ processor = $processor; $this->file = fopen(Shortcut::getUrl('access.log'), "a"); } - function execute(HTTPRequest $request) - { + function execute(HttpRequest $request) { $action = $request->getAction(); if(in_array($action, $this->before)) { - fwrite($this->file, "time: " . date("r", time()) . " query: ". json::encode(array_merge($_POST, $_GET)) . " by: " . UserAccess::$name . "\n"); + fwrite($this->file, "time: " . date("r", time()) . " query: ". json_encode(array_merge($_POST, $_GET)) . " by: " . Filter_UserAccess::$name . "\n"); } return $this->processor->execute($request); } diff --git a/src/Filter/Authorization.php b/src/Filter/Authorization.php new file mode 100644 index 0000000..17db6a6 --- /dev/null +++ b/src/Filter/Authorization.php @@ -0,0 +1,52 @@ +executeQuery("UPDATE visitor SET sid = '' WHERE id_visitor = " . $result->getInt('id_user')); + session_register("access"); + session_register("time"); + +// $_SESSION ["group"] = $result->getInt('access'); + $_SESSION ["access"] = $id; // id_user + $_SESSION [self::SESSION_BROWSER_SIGN_KEYNAME] = self::getBrowserSign(); + $_SESSION ["time"] = time(); + } + + private static function getBrowserSign() + { + $rawSign = self::SESSION_BROWSER_SIGN_SECRET; +// $signParts = array('HTTP_USER_AGENT', 'HTTP_ACCEPT_ENCODING'); + $signParts = array(); + + foreach ($signParts as $signPart) { + $rawSign .= '::' . (isset($_SERVER[$signPart]) ? $_SERVER[$signPart] : 'none'); + } + return md5($rawSign); + } + + static function logout() { + session_destroy(); + } +} diff --git a/core/filter/filterbase.php b/src/Filter/Filter.php similarity index 67% rename from core/filter/filterbase.php rename to src/Filter/Filter.php index d56c9e5..8140e8f 100644 --- a/core/filter/filterbase.php +++ b/src/Filter/Filter.php @@ -3,10 +3,10 @@ /** * Попытка реализовать фильтр для запросов */ -class Filter +class Filter_Filter { public $processor; - public function __construct($processor) + public function __construct(/*.Filter_Filter.*/$processor) { $this->processor = $processor; } @@ -16,9 +16,9 @@ class Filter return $this->processor->execute($request); } - public function getView($name) + public function getView($name, $class = 'View_Top') { - return $this->processor->getView($name); + return $this->processor->getView($name, $class); } public function getConnection() diff --git a/src/Filter/Login.php b/src/Filter/Login.php new file mode 100644 index 0000000..4ce7302 --- /dev/null +++ b/src/Filter/Login.php @@ -0,0 +1,177 @@ + "requiredcontent", "action" => "getcount")); + /** + * Проверка авторизации + * @return Boolean Авторизовани пользователь или нет + */ + public function isLoggin(HttpRequest $request) + { + // Авторизация + session_start(); + $db = $this->getConnection(); + Filter_UserAccess::setUp($db); // Соединение + switch ($request->getAction()) { + // Авторизация по постоянному паролю + case 'login': + $login = $request->get('login'); + $password = $request->get('password'); + + $result = Filter_UserAccess::getUserByLogin($login); // Поиск по логину + if ($result) { + $userPassword = $result->getString('password'); + if (Filter_UserAccess::$access == 'site_root' && defined('PARENT_PATH')) { + $s = new Settings(PARENT_PATH . '/settings.json'); + $s->read(); + $dsn = $s->readKey(array('system', 'dsn')); + + $db = Database::getConnection($dsn); + $user = $db->fetchOneArray("SELECT * FROM users WHERE login = :login", ['login' => $login]); + $userPassword = $user['password']; + } + // Извлечнеие пользователя из родительской CMS, для проверки пароля + if (md5($password) == $userPassword) { // password + $this->enter($db, $result); + return true; + } + } + $request->set('error', true); + break; + case 'logout': // Выход + session_destroy(); + break; + // Вход по временному паролю + case 'enter': + $login = $request->get('login'); + $password = $request->get('sid'); + $result = Filter_UserAccess::getUserByLogin($login); // Поиск по логину + if ($result) { + $temp = md5($result->getString('password') . $result->getString('login') . $result->getString('sid')); + if ($password == $temp) { + $this->enter($db, $result); + return true; + } + } + break; + default: + $hash = $this->getBrowserSign(); + // Если $hash не совпадает $_SESSION['hash'] то удаляем сессию + if (isset($_SESSION ['access']) && isset($_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME])) { + if ($hash == $_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME]) { + $this->user = $user = Filter_UserAccess::getUserById($_SESSION['access']); // Поиск по идентификатору + if ($user && isset($_SESSION['random']) && ($user->get('sid') == $_SESSION['random'])) { + return true; + } + return true; + } else { + session_destroy(); + } + } + } + return false; + } + + private function getBrowserSign() + { + $rawSign = self::SESSION_BROWSER_SIGN_SECRET; + //$signParts = array('HTTP_USER_AGENT', 'HTTP_ACCEPT_ENCODING'); + $signParts = array(); + + foreach ($signParts as $signPart) { + $rawSign .= '::' . (isset($_SERVER[$signPart]) ? $_SERVER[$signPart] : 'none'); + } + return md5($rawSign); + } + + private function enter($db, $result) + { + $this->user = $result; + $random = rand(0, 1024 * 1024); + $db->executeQuery("UPDATE users SET sid = '$random' WHERE id_user = " . $result->getInt('id_user')); + + $_SESSION["group"] = $result->getInt('access'); + $_SESSION["access"] = $result->getInt('id_user'); // id_user + $_SESSION["random"] = $random; // id_user + $_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME] = $this->getBrowserSign(); + $_SESSION["time"] = time(); + } + + public function execute(HttpRequest $request) + { + $logged = $this->isLoggin($request); + if ($request->get('action') == 'user_access') { + if ($logged) { + $result = array(); + $result['fullname'] = $this->user->getString('patronymic') . " " . $this->user->getString('firstname'); + $result['email'] = $this->user->getString('email'); + $result['site'] = 187; + $result['hash'] = sha1(self::SESSION_BROWSER_SIGN_SECRET . $this->user->getString('email')); + return json_encode($result); + } else { + return json_encode("NOT AUTHORIZED"); + } + } + + if ($request->get('action') == 'relogin') { + if ($logged) { + return json_encode(array('result' => 'ok', 'message' => "Авторизация успешна")); + } else { + return json_encode(array('result' => 'fail', 'message' => "Неправильное имя пользователя или пароль")); + } + } + + if (!$logged) { + // Параметры при неправильной авторизации + // Действия по умолчанию !! Возможно переход на форму регистрации + if ($request->get('mode') == 'ajax') { + if (!$this->requestIsWhite($request, $this->whiteRequestList)) { + return json_encode(array('result' => 'fail', 'message' =>"NOT_AUTHORIZED")); + } + } else { + $request->set('module', 'login'); + $request->set('mode', $this->mode); + } + } else if (isset($_SERVER['HTTP_REFERER'])) { + $arr = array(); + parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $arr); + if (isset($arr['back_page']) && $request->get('mode') != 'ajax') { + $request->redirect($arr['back_page']); + } + } + + $text = $this->processor->execute($request); + return $text; + } + + /* --------------------- + * Проверка на попадание реквеста в белый список + */ + + public function requestIsWhite(Collection $request, $whiteRequestList){ + $module = $request->get('module'); + $action = $request->get('action'); + foreach ($whiteRequestList as $whiteRequest) { + if ($module == $whiteRequest['module'] && $action == $whiteRequest['action']) { + return true; + } + } + + return false; + } +} + diff --git a/core/filter/filter.php b/src/Filter/UserAccess.php similarity index 85% rename from core/filter/filter.php rename to src/Filter/UserAccess.php index 126b21d..ce27a66 100644 --- a/core/filter/filter.php +++ b/src/Filter/UserAccess.php @@ -1,10 +1,7 @@ executeQuery(); @@ -65,7 +62,7 @@ class UserAccess $time = time(); if ($time - $lasttime > self::LIFE_TIME) return null; // Вышло время сессии $id = self::$id; - $stmt = self::$db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время последнего обращения входа + self::$db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время последнего обращения входа } return $result; } diff --git a/src/Form/Form.php b/src/Form/Form.php new file mode 100644 index 0000000..aa68acc --- /dev/null +++ b/src/Form/Form.php @@ -0,0 +1,394 @@ +default = null; + if (isset($input['validate'])) { + $this->require = strpos($input['validate'], 'require') !== false; + } + // Инициализация свойст обьетка + foreach (array('label', 'name', 'type', 'description') as $name) { + if (isset($input[$name])) { + $this->$name = $input[$name]; + } + } + } + + function setValue(/*.any.*/$value) + { + $this->value = $value; + } + + function getId() + { + return $this->name . '_label'; + } +} + +/** + * Поле ввода Input + */ +class TInput extends TField { +} + +class TCheckbox extends TField +{ + public $checked = false; + function setValue($value) + { + $this->value = $value; + $this->checked = $value; + } +} + + +class TSelect extends TField +{ + public $options = array(); + + public function __construct ($input, $factory) { + parent::__construct($input, $factory); + + if ($factory != null) { + $factory->create($this, $input); + } else if (isset($input['options.pair'])) { + $this->options = $this->optionsPair($input['options.pair']); + } else if (isset($input['options'])) { + $this->options = $input['options']; + } + + foreach ($this->options as &$option) { + $option['selected'] = false; + $option['class'] = (isset($option['class'])) ? $option['class'] : false; + } + } + + public function optionsPair($list, $selected = false) { + $result = array(); + foreach ($list as $key => $value) { + $result [] = array('value' => $key, 'name' => $value, 'selected' => $key == $selected); + } + return $result; + } +} + +/** + * Выбор из одного элемента + */ +class TSelectOne extends TSelect +{ + function setValue($value) + { + // Установить selected у options + $this->value = $value; + foreach ($this->options as &$option) { + $option['selected'] = ($option['value'] == $value); + } + } +} + +class TSelectMany extends TSelect +{ + function setValue($value) + { + // Установить selected у options + if (!is_array($value)) { $value = array($value); } + $this->value = $value; + foreach ($this->options as &$option) { + $option['selected'] = (in_array($option['value'], $value)); + } + } +} + +class TQuestionType extends TSelect +{ + function setValue($value) + { + // Установить selected у options + $this->value = $value; + foreach ($this->options as &$option) { + $option['selected'] = ($option['value'] == $value); + } + } +} + +/** + * Поле с датой + */ +class TDate extends TField +{ +} + +/** + * Поле с цветом + */ +class TColor extends TField +{ +} + + +/** + * Текстовое поле + */ +class TTextArea extends TField +{ + function setValue($value) + { + $this->value = $value; + } +} + +/** + * Поле для ввода пароля + */ +class TSecret extends TField +{ +} + +class TUpload extends TField +{ +} + +class THidden extends TInput { + public $hidden = true; +} + +class TComponentBrowserInput extends TInput +{ +} + +/** + * При рендеринге каждому классу соответствует шаблон (см. themes/maxim/templates/macros.html) + */ +class TDateTime extends TInput { +} + +class OptionFactory { + public $db; + + function __construct($db) { + $this->db = $db; + } + + function create(TSelect $field, $input) { + if (isset($input['options.resid'])) { + $type = $input['options.resid']; + + $res = new Model_Resources($this->db); + $field->options = $this->optionsArray('id_section', 'title', $res->getSubsections('', $type)); + + } else if (isset($input['options.res'])) { + $type = $input['options.res']; + + $res = new Model_Resources($this->db); + $field->options = $this->optionsArray('path', 'title', $res->getSubsections('', $type)); + + } else if (isset($input['options.all_res'])) { + $type = $input['options.all_res']; + + $res = new Model_Resources($this->db); + $field->options = $this->optionsArray('id_resource', 'subtitle', $res->getAllResource($type)); + + } else if (isset($input['options.db'])) { + list($table, $keyvalue) = explode(":", $input['options.db']); + list($key, $value) = explode(",", $keyvalue); + + $field->options = $this->optionsDB($key, $value, $this->db->executeQuery("SELECT * FROM $table")); + } elseif (isset($input['options.pair'])) { + $field->options = $this->optionsPair($input['options.pair']); + } else { + $field->options = $input['options']; + } + } + + public function optionsDB($key, $val, $res) { + $result = array(); + while($res->next()) { + $result[] = array('value' => $res->getInt($key), 'name' => $res->getString($val)); + } + return $result; + } + + public function optionsArray($key, $val, $res) { + $result = array(); + foreach($res as $item) { + $result[] = array('value' => $item->{$key}, 'name' => $item->{$val}); + } + return $result; + } + + public function optionsPair($list, $selected = false) { + $result = array(); + foreach ($list as $key => $value) { + $result [] = array('value' => $key, 'name' => $value, 'selected' => $key == $selected); + } + return $result; + } +} + +/** + * Форма для ввода + */ +class Form_Form extends View_View { + public $field = array(); + public $action = ""; + public $method = 'post'; + public $header; + + protected $replace; + protected $before; + + public $_title = array(); + public $alias = array(); + public $constructor = array(); + + /** + * Строим форму по ее структуре. Каждому типу соответствует определенный класс. + */ + public function __construct() + { + $this->constructor = array( + 'input' => 'TInput', + 'inputreq' => 'TInput', // input с проверкой на заполненность + + 'date' => 'TDate', + 'datereq' => 'TDate', + 'datetime' => 'TDateTime', + + 'color' => 'TColor', + 'textarea' => 'TTextArea', + 'text' => 'TTextArea', + 'multiselect' => 'TSelectMany', +// 'selectmany' => 'TSelectMany', + 'select1' => 'TSelectOne', + 'select' => 'TSelectOne', + 'questiontype'=> 'TQuestionType', + 'secret' => 'TSecret', + 'upload' => 'TUpload', + 'image' => 'TUpload', + 'checkbox' => 'TCheckbox', + 'checkmany' => 'TSelectMany', + 'hidden' => 'THidden', + 'radio' => 'TSelectOne', + 'filebrowser' => 'TComponentBrowserInput', + ); + + } + + function getId() + { + return '_form_edit'; + } + + public function addFieldClass($name, $class) + { + $this->constructor [$name] = $class; + } + + /** + * Добавляет одно поле ввода на форму + */ + public function addField(array $init, $factory = null) + { + assert(isset($init['type'])); + assert(isset($init['name'])); + +// print_r($init); + + $constructor = $this->constructor[$init['type']]; + $el = new $constructor($init, $factory); + if (!$el->type) { + $el->type = $init['type']; + } + + if(isset($init['hint'])) { + $el->hint = $init['hint']; + } + + $this->field [$init['name']] = $el; + return $el; + } + + /** + * Добавляет список полей для формы + * @param array $list + */ + public function addFieldList(array $list, $factory = null) + { + foreach ($list as $init) { + $this->addField($init, $factory); + } + } + + /** + * Устанавливает ошибки после проверки + */ + function setError(Validator_Validator $validator) + { + foreach ($validator->getErrorMsg() as $name => $error) + { + $this->field[$name]->error = true; + $this->field[$name]->error_msg = $error; + } + } + + function setFieldError($name, $message) + { + $this->field[$name]->error = true; + $this->field[$name]->error_msg = $message; + } + + /** + * Устанавливает значения из масива + */ + function setValues(HttpRequest $request) { + foreach ($this->field as $key => $el) { + $value = $request->getRawData($this->method, $key); + $this->field[$key]->setValue($value); + } + } + + /** + * Заполняет форму данными из обьекта + * @param object $data + * @param array $schema Связь между элементами формы и свойствами обьекта + */ + public function fill($data, array $schema) + { + foreach ($schema as $key => $conv) { + list($value, $type) = $conv; + $this->field [$key]->setValue(call_user_func(array('Primitive', 'from_' . $type), $data->$value)); + } + } + + public function set($name, $value) + { + $this->field[$name]->setValue($value); + } + + function execute() + { + return $this; + } +} diff --git a/core/form/viewstate.php b/src/Form/ViewState.php similarity index 92% rename from core/form/viewstate.php rename to src/Form/ViewState.php index c2ecaab..777618b 100644 --- a/core/form/viewstate.php +++ b/src/Form/ViewState.php @@ -4,7 +4,7 @@ * http://www.alternateinterior.com/2006/09/a-viewstate-for-php.html * Управление состоянием между страницами */ -class ViewState // extends Collection +class Form_ViewState // extends Collection { private $values = array(); @@ -13,7 +13,7 @@ class ViewState // extends Collection $this->values[$name] = $value; } - function get() + function get($_rest) { $args = func_get_args(); $result = $this->values; diff --git a/core/httprequest.php b/src/HttpRequest.php similarity index 78% rename from core/httprequest.php rename to src/HttpRequest.php index 44571ec..7693177 100644 --- a/core/httprequest.php +++ b/src/HttpRequest.php @@ -1,8 +1,5 @@ isAjax(); foreach ($list as $key => $value) { - $data = new SafeCollection(); + $data = new Collection(); $data->import($value); - parent::set($key, $data); } @@ -38,50 +36,32 @@ class HttpRequest extends Collection implements ArrayAccess parent::set('files', $data); } - function get($key, $default = null) - { - return parent::get('data')->get($key, $default); - } - - function session($value = false) - { - if ($value) { - $this->session = $value; - } - return $this->session; - } - - function set($key, $value) - { - return parent::get('data')->set($key, $value); - } - - function _get($key) { return parent::get($key); } - function export() + function get($key, $default = null) { - return parent::get('data')->export(); + return parent::get('data')->get($key, $default); + } + + function session(Session $value = null) + { + if ($value) { + $this->_session = $value; + } + return $this->_session; } - /* Array Acces Interface */ - function offsetExists($offset) + function set($key, /*.any.*/$value) { + return parent::get('data')->set($key, $value); } - function offsetGet($offset) - { - } - - function offsetSet($offset, $value) - { - } - - function offsetUnset($offset) + function export($key = 'data') { + return parent::get($key)->export(); } function clear() @@ -128,4 +108,22 @@ class HttpRequest extends Collection implements ArrayAccess { return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'); } + + public function redirect($url) { + header('location: ' . $url); + exit(); + } + + + public function offsetSet($key, $value) { + } + + public function offsetExists($key) { + } + + public function offsetUnset($key) { + } + + public function offsetGet($key) { + } } diff --git a/src/Layout/Empty.php b/src/Layout/Empty.php new file mode 100644 index 0000000..a7f99b8 --- /dev/null +++ b/src/Layout/Empty.php @@ -0,0 +1,13 @@ +processor->execute($request); + return $text; + } +} diff --git a/core/layout/layout.php b/src/Layout/Manager.php similarity index 80% rename from core/layout/layout.php rename to src/Layout/Manager.php index 7c13029..965207d 100644 --- a/core/layout/layout.php +++ b/src/Layout/Manager.php @@ -1,13 +1,13 @@ 'personal'), 'personal') * addConditionGet(array('module' => 'login'), 'login') */ - public function addConditionGet($get, Filter $layout) + public function addConditionGet($get, Filter_Filter $layout) { $this->addCondition(rcurry(array($this, 'checkGet'), $get), $layout); } @@ -28,7 +28,7 @@ class LayoutManager extends Filter /** * Условие для аякс запросов. Тоже самое что и addConditionGet но еще проверяется является ли запрос ajax */ - public function addConditionXHR($get, Filter $layout) + public function addConditionXHR($get, Filter_Filter $layout) { $this->addCondition(rcurry(array($this, 'checkXHR'), $get), $layout); } @@ -51,11 +51,11 @@ class LayoutManager extends Filter } /** - * Добавляет есловие в общем виде + * Добавляет условие в общем виде * @parma $get function(HttpRequest) Функция * @parma $layout Layout Макет */ - public function addCondition($get, Filter $layout) + public function addCondition($get, Filter_Filter $layout) { $this->condition [] = array($get, $layout); } @@ -69,8 +69,7 @@ class LayoutManager extends Filter if (call_user_func($condition[0], $request)) { $layout = $condition[1]; $view = $layout->execute($request); - - if ($view instanceof View_Composite) { + if (is_object($view)) { echo $view->render(); } else { echo $view; @@ -81,13 +80,3 @@ class LayoutManager extends Filter } } -/** - * Самый простой макет - */ -class LayoutNone extends Filter -{ - function execute(HttpRequest $request) - { - return $this->processor->execute($request); - } -} diff --git a/core/mail.php b/src/Mail.php similarity index 76% rename from core/mail.php rename to src/Mail.php index 3bd2ef1..f27a0a8 100644 --- a/core/mail.php +++ b/src/Mail.php @@ -6,14 +6,14 @@ */ class Mail { - public $from; - public $to; - public $subject; + public $_from; + public $_to; + public $_subject; public $content; public $copy; private $encoding; - private $notify= false; + private $_notify = null; protected $attachment = array (); protected $uniqid; @@ -22,8 +22,6 @@ class Mail function __construct() { $this->setEncoding("UTF-8"); $this->uniqid = strtoupper(uniqid(time())); // Идентефикатор разделителя - -// $this->mime } /** @@ -31,7 +29,7 @@ class Mail */ function from($name) { - $this->from = $name; + $this->_from = $name; } /** @@ -39,7 +37,7 @@ class Mail */ function to($name) // recipient { - $this->to = $name; + $this->_to = $name; } /** @@ -52,7 +50,7 @@ class Mail function notify($notify) { - $this->notify = $notify; + $this->_notify = $notify; } /** @@ -60,7 +58,7 @@ class Mail */ function subject($subject) { - $this->subject = $subject; + $this->_subject = $subject; } /** @@ -70,12 +68,7 @@ class Mail { $this->content = $text; } - - function setType($type) - { - $this->type = $type; - } - + /** * Кодировка текста в письме */ @@ -93,11 +86,18 @@ class Mail if(file_exists($filename)) { // assert ?? $file = fopen($filename, "rb"); - $data = fread($file, filesize($filename)); - $this->attachment [] = ($name) ? array($data, $name) : array($data, basename($filename)); + if (is_resource($file)) { + $data = fread($file, filesize($filename)); + $this->attachment [] = ($name) ? array($data, $name) : array($data, basename($filename)); + } } } + function setType($type) + { + $this->type = $type; + } + /** * Добавление вложения из строки с указанием имени файла */ @@ -115,7 +115,7 @@ class Mail /** * Общий формат тегов MIME - * http://tools.ietf.org/html/rfc2045 + * @see http://tools.ietf.org/html/rfc2045 */ function mimeTag($name, $value, array $args = array()) { @@ -127,7 +127,7 @@ class Mail /** * - * http://tools.ietf.org/html/rfc2047 + * @see http://tools.ietf.org/html/rfc2047 */ function encodedWord($text, $encoding = 'B') { @@ -144,16 +144,16 @@ class Mail $message .= $this->mimeTag("Content-Transfer-Encoding", "8bit"); $message .= PHP_EOL . $this->content . PHP_EOL . PHP_EOL; - /** + /* * Вложения * http://tools.ietf.org/html/rfc2046#section-5.1.3 */ foreach ($this->attachment as $value) { list($data, $name) = $value; $message .= "--" . $this->uniqid . PHP_EOL; - $message .= $this->mimeTag("Content-Type", "application/octet-stream", array ('name' => $name)); + $message .= $this->mimeTag("Content-Type", "application/octet-stream", array ('name' => basename($name))); $message .= $this->mimeTag("Content-Transfer-Encoding", "base64"); - $message .= $this->mimeTag("Content-Disposition", "attachment", array ('filename' => $name)); + $message .= $this->mimeTag("Content-Disposition", "attachment", array ('filename' => basename($name))); $message .= PHP_EOL . chunk_split(base64_encode($data)) . PHP_EOL; } @@ -166,11 +166,11 @@ class Mail function getHeader() { $head = $this->mimeTag("MIME-Version", "1.0"); - $head .= $this->mimeTag("From", $this->from); - $head .= $this->mimeTag("X-Mailer", "CIS Tool"); - $head .= $this->mimeTag("Reply-To", $this->from); - if ($this->notify) { - $head .= $this->mimeTag("Disposition-Notification-To", "\"" . $this->notify . "\" <" . $this->from . ">"); + $head .= $this->mimeTag("From", $this->_from); + $head .= $this->mimeTag("X-Mailer", "CMS Tool"); + $head .= $this->mimeTag("Reply-To", $this->_from); + if (is_string($this->_notify)) { + $head .= $this->mimeTag("Disposition-Notification-To", "\"" . $this->_notify . "\" <" . $this->_from . ">"); } $head .= $this->mimeTag("Content-Type", "multipart/mixed", array ("boundary" => $this->uniqid)); if ($this->copy) { @@ -182,7 +182,7 @@ class Mail function getSubject() { - return $this->encodedWord($this->subject); + return $this->encodedWord($this->_subject); } /** @@ -190,7 +190,7 @@ class Mail */ function eml() { - return "To: " . $this->to . PHP_EOL . "Subject: {$this->getSubject()}" . PHP_EOL . $this->getHeader() . $this->getMessage(); + return "To: " . $this->_to . PHP_EOL . "Subject: {$this->getSubject()}" . PHP_EOL . $this->getHeader() . $this->getMessage(); } /** @@ -198,11 +198,10 @@ class Mail */ function send() { - $result = mail($this->to, $this->getSubject(), $this->getMessage(), $this->getHeader()); + $result = mail($this->_to, $this->getSubject(), $this->getMessage(), $this->getHeader()); if(! $result) { - throw new Exception('Невозможно отправить почту'); -// require_once "core/path.php"; -// file_put_contents(Path::resolveFile("data/email/send.eml"), $this->eml()); + file_put_contents(Path::resolveFile("send.eml"), $this->eml()); + throw new Exception('Невозможно отправить почту'); } return $result; } diff --git a/core/numbers.php b/src/Numbers.php similarity index 84% rename from core/numbers.php rename to src/Numbers.php index bd0adea..c0a39c7 100644 --- a/core/numbers.php +++ b/src/Numbers.php @@ -12,7 +12,7 @@ class Numbers return $i; } - static function prefix($prefix, array $array) + static function prefix($prefix, array $array, $key = false) { $result = array(); for ($i = 0; $i < count($array); $i++) { diff --git a/src/Path.php b/src/Path.php new file mode 100644 index 0000000..1a74881 --- /dev/null +++ b/src/Path.php @@ -0,0 +1,430 @@ +url = parse_url($path); + + if (isset($this->url['path'])) { + $path = $this->url['path']; +// $path = preg_replace('/\/{2,}/', '/', $path); + $this->path = self::optimize($this->fromString($path)); + } + } + + static function factory($path) { + return new Path($path); + } + + public function getParts() + { + return $this->path; + } + + public static function normalize($pathName) + { + $path = new Path($pathName); + return $path->__toString(); + } + + /** + * Базовое имя + * @param $path + * @return mixed + */ + public static function basename($path) + { + $list = preg_split('#\\\\|/#s', $path); + return end($list); + } + + /** + * Возвращает расширение файла + * + * @param string $fileName Полное имя файла + * + * @return string + */ + static function getExtension($fileName) + { + assert(is_string($fileName) || is_null($fileName)); + + return pathinfo($fileName, PATHINFO_EXTENSION); + } + + static function isType($fileName, $extension) + { + if (is_array($extension)) { + return in_array(pathinfo($fileName, PATHINFO_EXTENSION), $extension); + } else { + return (pathinfo($fileName, PATHINFO_EXTENSION) == $extension); + } + } + + /** + * Полное имя файла без расширения + * + * @param string $fileName Имя файла + * + * @return string + */ + static function skipExtension($fileName) + { + assert(is_string($fileName)); + + $path = pathinfo($fileName); + if ($path['dirname'] == ".") { + return $path['filename']; + } else { + return self::join($path['dirname'], $path['filename']); + } + } + + /** + * Возвращает имя файла без расширения + * + * @param string $fileName Полное имя файла + * + * @return string + */ + static function getFileName($fileName) + { + assert(is_string($fileName)); + + return pathinfo($fileName, PATHINFO_FILENAME); + } + + + /** + * Преобразует строку путя в массив + * + * @param string $path Путь + * + * @return array + */ + public function fromString ($path) + { + assert(is_string($path)); + + $list = preg_split('#\\\\|/#s', $path); + if (isset($this->url['scheme']) && !isset($this->url['host'])) { + $this->absolute = false; + } else if ($list[0] == '' && count($list) > 1) { + $this->absolute = true; + } + + return $list; + } + + /** + * Преобразует относительный путь в абсолютный + */ + public static function optimize($path) // + { + $result = array(); + foreach ($path as $n) { + switch ($n) { + // Может быть относительным или абсолютным путем + case "": break; + case ".": break; + case "..": + if (count($result) > 0) { array_pop($result); break; } + default: + array_push($result, $n); + } + } + return $result; + } + + // Сравнение двух путей на равентство + public function equal(/*.Path.*/ $path) + { + if (count($this->path) == count($path->path)) { + for ($i = 0; $i < count($this->path); $i++) { + if ($this->path[$i] != $path->path[$i]) { + return false; + } + } + return true; + } + return false; + } + + public static function makeUrl($path) + { + return (isset($path['scheme']) ? $path['scheme'] . ':/' : '') + . (isset($path['host']) ? ('/' + . (isset($path['user']) ? $path['user'] . (isset($path['pass']) ? ':' . $path['pass'] : '') . '@' : '') + . $path['host'] + . (isset($path['port']) ? ':' . $path['port'] : '')) : '') + . $path['path'] + . (isset($path['query']) ? '?' . $path['query'] : '') + . (isset($path['fragment']) ? '#' . $path['fragment'] : ''); + } + + /** + * Преобразует путь в строку + * + * @return string + */ + public function __toString() + { + $result = (($this->absolute) ? '/' : '') . implode(self::SEPARATOR, $this->path); + $this->url['path'] = $result; + return self::makeUrl($this->url); + } + + /** + * Проверяет является ли папка родительской для другой папки + * + * @parma Path $path + * + * @return boolean + */ + public function isParent(/*.Path.*/ $path) + { + if (isset($this->url['host']) && isset($path->url['host']) + && ($this->url['host'] != $path->url['host'])) return false; + + if (count($path->path) > count($this->path)) { + for ($i = 0; $i < count($this->path); $i++) { + if ($path->path[$i] != $this->path[$i]) { + return false; + } + } + return true; + } + return false; + } + + public static function _isParent($path1, $path2) + { + $path = new Path($path1); + return $path->isParent(new Path($path2)); + } + + /** + * Находит путь относительно текущего путя + * + * @param string $name Полный путь к файлу + * + * @return string Относительный путь к файлу + */ + public function relPath($name) + { + $path = new Path($name); + unset($path->url['scheme']); +// $this->absolute = false; + $path->absolute = false; + foreach ($this->path as $n) { + array_shift($path->path); + } + return $path->__toString(); + } + + // Вычисляет относительный путь в виде строки + static function relative($rpath, $lpath) { + // Нужно проверять диск!! + $self = new Path($rpath); + $list = new Path($lpath); + $self_path = $self->getParts(); + $list_path = $list->getParts(); + + $result = array(); + for ($i = 0; $i < count($list_path); $i++) { + if (($i >= count($self_path)) || $list_path[$i] != $self_path[$i]) { + break; + } + } + for($j = $i; $j < count($list_path); $j++) { + array_push($result, '..'); + } + for($j = $i; $j < count($self_path); $j++) { + array_push($result, $self_path[$j]); + } + return implode("/", $result); + } + + public function append($path) + { + $base = $this->__toString(); + return self::join($base, $path); + } + + + /** + * Обьединяет строки в путь соединяя необходимым разделителем + * fixme не обрабатывает параметры урла, решение Path::join(SITE_WWW_PATH) . '?param=pampam' + * @return string + */ + static function join($_rest) + { + $args = func_get_args(); + $result = array(); + $parts0 = new Path(array_shift($args)); + $result [] = $parts0->getParts(); + foreach ($args as $file) { + $parts = new Path($file); + $result [] = $parts->getParts(); + } + // При обьединении ссылок можно обьеденить path, query, fragment + $path = implode(self::SEPARATOR, call_user_func_array('array_merge', $result)); + $parts0->url['path'] = ($parts0->isAbsolute()) ? '/' . $path : $path; + return self::makeUrl($parts0->url); + } + + // Проверка структуры имени файла + static function checkName($name, $extension) + { + return (strlen(pathinfo($name, PATHINFO_FILENAME)) > 0) && (pathinfo($name, PATHINFO_EXTENSION) == $extension); + } + + static function isCharName($char) + { + $ch = ord($char); + return ((($ch >= ord('a')) && ($ch <= ord('z'))) || (strpos('-._', $char) !== false) || (($ch >= ord('0')) && ($ch <= ord('9')))); + } + + // Проверка имени файла + static function isName($name) { + if (strlen(trim($name)) == 0) { + return false; + } + for ($i = 0; $i < strlen($name); $i++) { + if (!self::isCharName($name[$i])) { + return false; + } + } + return true; + } + + public function isAbsolute() + { + return $this->absolute; + } + + /** + * Подбирает новое временное имя для файла + * + * @param string $dst Предпологаемое имя файла + * + * @return string Новое имя файла + */ + static function resolveFile($dst) + { + $i = 0; + $file = self::skipExtension($dst); + $suffix = self::getExtension($dst); + $temp = $dst; + while (file_exists($temp)) { + $i ++; + $temp = $file . "." . $i . "." . $suffix; + } + return $temp; + } + + + /** + * Список файлов в директории + * + * @param array $allow массив расширений для файлов + * @param array $ignore массив имен пааок которые не нужно обрабатывать + * + * @returnarray + */ + public function getContent($allow = null, $ignore = array()) + { + $ignore = array_merge(array(".", ".."), $ignore); + return self::fileList($this->__toString(), $allow, $ignore); + } + + /** + * Обьединяет строки в путь соединяя необходимым разделителем + * + * @param array $allow массив расширений разрешеных для файлов + * @param array $ignore массив имен пааок которые не нужно обрабатывать + * + * @return array + */ + function getContentRec($allow = null, $ignore = array()) + { + $result = array (); + $ignore = array_merge(array (".", ".."), $ignore); + self::fileListAll($result, $this->__toString(), $allow, $ignore); + return $result; + } + + // Использовать SPL ??? + protected static function fileList($base, &$allow, &$ignore) + { + if ($base == '') $base = '.'; + $result = array (); + $handle = opendir($base); + if (is_resource($handle)) { + while (true) { + $file = readdir($handle); + if (is_string($file)) { + if (! in_array($file, $ignore)) { + $isDir = is_dir(Path::join($base, $file)); + if ($isDir || ($allow == null) || in_array(self::getExtension($file), $allow)) { + $result[] = $file; + } + } + continue; + } + break; + } + closedir($handle); + } + // При обьединении ссылок можно обьеденить path, query, fragment + return $result; + } + + protected static function fileListAll(&$result, $base, &$allow, &$ignore) + { + $files = self::fileList($base, $allow, $ignore); + foreach ($files as $name) { + $fullname = self::join($base, $name); + if (is_dir($fullname)) { + self::fileListAll($result, $fullname, $allow, $ignore); + } else { + array_push($result, $fullname); + } + } + } + + /** + * Создает недастающие папки для записи файла + * + * @param string $dst Полное имя файла + * + * @return void + */ + static function prepare($dst, $filename = true) + { + if ($filename) { + $path_dst = pathinfo($dst, PATHINFO_DIRNAME); + } else { + $path_dst = $dst; + } + if (! file_exists($path_dst)) { + mkdir($path_dst, 0777, true); + } + } +} + diff --git a/src/Primitive.php b/src/Primitive.php new file mode 100644 index 0000000..aec45fd --- /dev/null +++ b/src/Primitive.php @@ -0,0 +1,119 @@ + 0) { + return date("d/m/Y", $value); + } + return ''; + } + + public static function from_datetime($value) + { + if ($value > 0) { + return date("Y-m-d\TH:i\Z", $value); + } + return ''; + } + + + // secure + public static function to_secure($value) + { + // Значение приабразуется во время сохранения в базе данных + return $value; + } + + public static function from_secure($value) + { + return $value; + } + + // array + public static function to_array($value) + { + return (is_array($value)) ? $value : array(); + } + + public static function from_array($value) + { + return $value; + } +} + diff --git a/core/registry.php b/src/Registry.php similarity index 92% rename from core/registry.php rename to src/Registry.php index 661dad5..f2b7673 100644 --- a/core/registry.php +++ b/src/Registry.php @@ -1,11 +1,12 @@ + /** * http://www.patternsforphp.com/wiki/Registry * http://www.patternsforphp.com/wiki/Singleton * http://www.phppatterns.com/docs/design/the_registry?s=registry */ -require_once 'core/settings.php'; class Registry extends Settings { diff --git a/core/session.php b/src/Session.php similarity index 95% rename from core/session.php rename to src/Session.php index 2d2b666..43ec665 100644 --- a/core/session.php +++ b/src/Session.php @@ -26,7 +26,7 @@ class Session function start() { - session_start(); + @session_start(); } function stop() diff --git a/core/settings.php b/src/Settings.php similarity index 82% rename from core/settings.php rename to src/Settings.php index 35de901..ee1fc2d 100644 --- a/core/settings.php +++ b/src/Settings.php @@ -1,7 +1,5 @@ format = pathinfo($file, PATHINFO_EXTENSION); $this->file = $file; } /** * Чтение настроек из файла - * - * @param File $file - * * @return Boolean */ public function read() { - if ( !file_exists ($this->file)) return false; + if (!file_exists ($this->file)) { + return false; + } // Не include_once т.к читать настройки можно несколько раз - include($this->file); + $settings = array(); + if ($this->format == 'json') { + $settings = json_decode(file_get_contents($this->file), true); + } else { + include ($this->file); + } + if (!is_array($settings)) { throw new Exception($this->file); } @@ -53,7 +59,9 @@ class Settings extends Collection // assert(count($key) == 1); $name = array_shift($key); if (is_array($value)) { - if (! isset($data[$name])) $data[$name] = array(); + if (!isset($data[$name])) { + $data[$name] = array(); + } $this->merge($data[$name], $value); } else { $data[$name] = $value; @@ -109,7 +117,7 @@ class Settings extends Collection * Чтение ключа из реестра (Собирает все ключи с определенным значением во всех модулях) * @param $key Путь к значению ключа внутри модуля */ - public function readKeyList() + public function readKeyList($_rest) { $key = func_get_args(); $result = array(); @@ -151,10 +159,15 @@ class Settings extends Collection * * @return void */ - public function write($file = false) + public function write($file = null) { - $result = var_export ($this->data, true); - file_put_contents (($file) ? $file : $this->file, ""); + if ($this->format == 'json') { + $result = json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + } else { + $result = var_export($this->data, true); + $result = ""; + } + file_put_contents (($file) ? $file : $this->file, $result); } /** diff --git a/src/Setup.php b/src/Setup.php new file mode 100644 index 0000000..c3c754c --- /dev/null +++ b/src/Setup.php @@ -0,0 +1,212 @@ + + * $setup = new Setup('test.xml'); + * $setup->set('target', 'dst'); + * $setup->executeActions('install'); + * + */ +class Setup +{ + protected $actions = array(); + public $context = array(); + protected $file; + protected $action; + protected $node; + protected $stack = array(); + + public $zip; + public $target; + + public function __construct($file) + { + $this->file = $file; + $this->node = simplexml_load_file($file); + + $this->target = ''; + $this->zip = new ZipArchive(); + $this->zip->open(strtr($file, array('.xml' => '.zip'))); + + + array_push($this->stack, $this->node); + + $this->registerAction('copy', array($this, 'copyFile')); + $this->registerAction('make-directory', array($this, 'makeDirectory')); + $this->registerAction('make-link', array($this, 'makeLink')); + $this->registerAction('include', array($this, 'includeFile')); + $this->registerAction('when', array($this, 'testWhen')); + } + + /** + * Регистрация новых действия для установки + */ + public function registerAction($name, $action) + { + $this->actions[$name] = $action; + } + + /** + * Установка переменных для шаблона + */ + public function set($name, $value) + { + $this->context[$name] = $value; + } + + function replaceFn($matches) { + if (isset($this->context[$matches[2]])) { + $v = $this->context[$matches[2]]; + } else { + $v = $matches[2]; + } + + if ($matches[1] == '*') { + return addslashes($v); + } + return $v; + } + + public function fileContent($file, array $tpl) + { + $result = $this->zip->getFromName($file); + $result = preg_replace_callback('/\{\{\s*(\*?)(\w+)\s*\}\}/', array($this, 'replaceFn'), $result); + return $result; + } + + function callAction($name, array $attributes) + { + if(isset($this->actions[$name])) { + call_user_func_array($this->actions[$name], $attributes); + } + } + + /** + * Заменяет переменные на их значения в строке + */ + function replaceVariable(array $match) + { + if (isset($this->context[$match[1]])) { + return $this->context[$match[1]]; + } + return $match[0]; + } + + /** + * Для всех аттрибутов заменяет переменные на их значения + */ + function resolve($attributes) + { + $result = array(); + foreach ($attributes as $key => $value) { + $result [$key] = preg_replace_callback("/\\\${(\w+)}/", array($this, 'replaceVariable'), $value); + } + return $result; + } + + /** + * Выполняет список действий если для действия не указан аттрибут when то оно выполняется всегда + * + * @param $action специальное действие + */ + function executeActions($action = "install") + { + $this->action = $action; + if ($this->stack[count($this->stack) - 1] === false) { + return; + } + + /*.SimpleXMLElement.*/$item = $this->stack[count($this->stack) - 1]; + $root = $item->children(); + foreach ($root as $node) + { + $attributes = $node->attributes(); + array_push($this->stack, $node); + $this->callAction($node->getName(), array($this->resolve($attributes))); + array_pop($this->stack); + } + } + + /** + * Копирования файла + * @param preserve Не переписывать файл если он существует + * @param template Файл является шаблоном подставить параметры до копирования + * @param src Исходный файл + * @param dst Новый файл + */ + public function copyFile(array $attributes) + { + $path = $this->targetPath($attributes['dst']); + + if (!(file_exists($path) && isset($attributes['preserve']))) { + file_put_contents($path, $this->fileContent($attributes['src'], $this->context)); + } + } + + /** + * Создает символическую ссылку на папку/файл + * @param dst Имя папки + */ + public function makeLink(array $attributes) + { + if (function_exists('symlink')) { + symlink($attributes['target'], $attributes['link']); + } + } + + /** + * Подключение файла установки + * @param file Имя подключаемого файла + */ + public function includeFile(array $attributes) + { + $file = basename($this->file) . "/" . $attributes['file']; + + $setup = new Setup($file); + $setup->context = $this->context; + $setup->executeActions(); + } + + function targetPath($s) { + return $this->target . '/' . $s; + } + + /** + * Создает новую папку + * @param dst Имя папки + */ + public function makeDirectory(array $attributes) + { + $path = $this->targetPath($attributes['dst']); + if (!file_exists($path)) { + mkdir($path); + } + } + + function testWhen(array $attributes) + { + if (!isset($attributes['test']) || $attributes['test'] == $this->action) { + $this->executeActions($this->action); + } + } + + /** + * Выполнение Списка SQL команд + */ + function batchSQLZip(/*.Database.*/ $conn, $file) + { + $stmtList = Tools_SQLStatementExtractor::extract($this->zip->getFromName($file)); + foreach ($stmtList as $stmt) { + $conn->executeQuery ($stmt); + } + } + + static function batchSQL(/*.Database.*/ $conn, $file) + { + $stmtList = Utils_SQLStatementExtractor::extractFile($file); + foreach ($stmtList as $stmt) { + $conn->executeQuery ($stmt); + } + } +} + diff --git a/core/shortcut.php b/src/Shortcut.php similarity index 77% rename from core/shortcut.php rename to src/Shortcut.php index a80e5f5..4e24046 100644 --- a/core/shortcut.php +++ b/src/Shortcut.php @@ -10,7 +10,7 @@ class Shortcut public $list = array(); // Singleton pattern - static public function getInstance () + static public function getInstance() { if (self::$instance == null) { self::$instance = new Shortcut(); @@ -24,7 +24,7 @@ class Shortcut */ public function addUrl($prefix, $path) { - $this->list [$prefix] = $path; + $this->list[$prefix] = $path; } /** @@ -38,9 +38,10 @@ class Shortcut /** * Возвращает путь по имени ярлыка */ - static function getUrl ($prefix, $name = null, $name1 = false) + static function getUrl($prefix, $name = null, $name1 = null) { $shortcut = self::getInstance(); + $names = $shortcut->variables; if ($name) { $names['$name'] = $name; @@ -48,10 +49,18 @@ class Shortcut if ($name1) { $names['$name1'] = $name1; } + if (isset($shortcut->list[$prefix])) { return strtr($shortcut->list[$prefix], $names); } - return false; + return null; } -} + static function expand($path) + { + $shortcut = self::getInstance(); + $names = $shortcut->variables; + return strtr($path, $names); + } + +} diff --git a/core/sort.php b/src/SortRecord.php similarity index 96% rename from core/sort.php rename to src/SortRecord.php index 083c00c..24c054b 100644 --- a/core/sort.php +++ b/src/SortRecord.php @@ -2,6 +2,10 @@ class SortRecord { + public $key; + public $mode; + public $order; + function __construct($key, $mode, $order) { $this->key = $key; diff --git a/core/tools/drawing.php b/src/Tools/Drawing.php similarity index 96% rename from core/tools/drawing.php rename to src/Tools/Drawing.php index b0cf247..e13a323 100644 --- a/core/tools/drawing.php +++ b/src/Tools/Drawing.php @@ -1,8 +1,7 @@ ", $font, "\n"; $dimensions = imagettfbbox($size, $angle, $font, $current_line . ($first_word ? '' : ' ') . $item); $line_width = $dimensions[2] - $dimensions[0]; $line_height = $dimensions[1] - $dimensions[7]; @@ -75,6 +72,7 @@ class Drawing } // vertical align + $top_offset = 0; if ($valign == self::ALIGN_CENTER) { $top_offset = ($max_height - $largest_line_height * count($lines)) / 2; } elseif ($valign == self::ALIGN_BOTTOM) { @@ -84,17 +82,15 @@ class Drawing $top += $largest_line_height + $top_offset; $i = 0; - fb($lines); - fb($line_widths); foreach ($lines as $line) { // horizontal align + $left_offset = 0; if ($align == self::ALIGN_CENTER) { $left_offset = ($max_width - $line_widths[$i]) / 2; } elseif ($align == self::ALIGN_RIGHT) { $left_offset = ($max_width - $line_widths[$i]); } -// echo $font, "\n"; imagettftext($image, $size, $angle, $left + $left_offset, $top + ($largest_line_height * $i), $color, $font, $line); $i++; } diff --git a/core/tools/image.php b/src/Tools/Image.php similarity index 98% rename from core/tools/image.php rename to src/Tools/Image.php index 04350a1..c9c10ef 100644 --- a/core/tools/image.php +++ b/src/Tools/Image.php @@ -1,6 +1,6 @@ 1 && !$force) $percent = 1; $new_width = $width * $percent; diff --git a/src/Tools/SQLStatementExtractor.php b/src/Tools/SQLStatementExtractor.php new file mode 100644 index 0000000..551ee85 --- /dev/null +++ b/src/Tools/SQLStatementExtractor.php @@ -0,0 +1,164 @@ +. + */ + +/** + * Static class for extracting SQL statements from a string or file. + * + * @author Hans Lellelid + * @version $Revision: 1.5 $ + * @package creole.util.sql + */ +class Tools_SQLStatementExtractor { + + protected static $delimiter = ';'; + + /** + * Get SQL statements from file. + * + * @param string $filename Path to file to read. + * @return array SQL statements + */ + public static function extractFile($filename) { + $buffer = file_get_contents($filename); + if ($buffer === false) { + throw new Exception("Unable to read file: " . $filename); + } + return self::extractStatements(self::getLines($buffer)); + } + + /** + * Extract statements from string. + * + * @param string $txt + * @return array + */ + public static function extract($buffer) { + return self::extractStatements(self::getLines($buffer)); + } + + /** + * Extract SQL statements from array of lines. + * + * @param array $lines Lines of the read-in file. + * @return string + */ + protected static function extractStatements($lines) { + + $statements = array(); + $sql = ""; + + foreach($lines as $line) { + + $line = trim($line); + + if (self::startsWith("//", $line) || + self::startsWith("--", $line) || + self::startsWith("#", $line)) { + continue; + } + + if (strlen($line) > 4 && strtoupper(substr($line,0, 4)) == "REM ") { + continue; + } + + $sql .= " " . $line; + $sql = trim($sql); + + // SQL defines "--" as a comment to EOL + // and in Oracle it may contain a hint + // so we cannot just remove it, instead we must end it + if (strpos($line, "--") !== false) { + $sql .= "\n"; + } + + if (self::endsWith(self::$delimiter, $sql)) { + $statements[] = self::substring($sql, 0, strlen($sql)-1 - strlen(self::$delimiter)); + $sql = ""; + } + } + return $statements; + } + + // + // Some string helper methods + // + + /** + * Tests if a string starts with a given string. + * @param string $check The substring to check. + * @param string $string The string to check in (haystack). + * @return boolean True if $string starts with $check, or they are equal, or $check is empty. + */ + protected static function startsWith($check, $string) { + if ($check === "" || $check === $string) { + return true; + } else { + return (strpos($string, $check) === 0) ? true : false; + } + } + + /** + * Tests if a string ends with a given string. + * @param string $check The substring to check. + * @param string $string The string to check in (haystack). + * @return boolean True if $string ends with $check, or they are equal, or $check is empty. + */ + protected static function endsWith($check, $string) { + if ($check === "" || $check === $string) { + return true; + } else { + return (strpos(strrev($string), strrev($check)) === 0) ? true : false; + } + } + + /** + * a natural way of getting a subtring, php's circular string buffer and strange + * return values suck if you want to program strict as of C or friends + */ + protected static function substring($string, $startpos, $endpos = -1) { + $len = strlen($string); + $endpos = (int) (($endpos === -1) ? $len-1 : $endpos); + if ($startpos > $len-1 || $startpos < 0) { + trigger_error("substring(), Startindex out of bounds must be 0 $len-1 || $endpos < $startpos) { + trigger_error("substring(), Endindex out of bounds must be $startpos 0) { // already in sub-array? + $subarr[$in_subarr][] = $tok; + if ('}' === substr($tok, -1, 1)) { // check to see if we just added last component + $res[] = strToArray(implode(',', $subarr[$in_subarr])); + $in_subarr--; + } + } elseif ($tok{0} === '{') { // we're inside a new sub-array + if ('}' !== substr($tok, -1, 1)) { + $in_subarr++; + // if sub-array has more than one element + $subarr[$in_subarr] = array(); + $subarr[$in_subarr][] = $tok; + } else { + $res[] = strToArray($tok); + } + } else { // not sub-array + $val = trim($tok, '"'); // remove " (surrounding strings) + // perform type castng here? + $res[] = $val; + } + } + + return $res; +} + +//Нормализация строк на русском +function normalizeRussian($str) { + $result = preg_replace('/\s+/',' ', $str); + if (is_string($result)) { + $result = trim($result); //Замена длинных пробелов на одинарные, пробелы по краям + $result = mb_strtolower($result); + $result = preg_replace('/ё/','е', $str); //е на ё + } + return $result; +} + +//Проверка равенства двух строк на русском языке. +function equalRussianCheck($str1,$str2) { + return normalizeRussian($str1) == normalizeRussian($str2); +} + + +/** + * Попадает ли строка в список вариантов + * input: $str="foo1" $variants="foo1|foo2|foo3" + * output: true + * input: $str="foo" $variants="foo1|foo2|foo3" + * output: false +*/ +function compare_string_to_variants($str, $variants){ + $variants_array = explode('|', $variants); + $founded = false; + foreach ($variants_array as $variant) { + $founded = $founded || equalRussianCheck($variant, $str); + } + return $founded; +} + +function mb_str_split($str) { + return preg_split('~~u', $str, null, PREG_SPLIT_NO_EMPTY); +} + +function mb_strtr($str, $from, $to) { + return str_replace(mb_str_split($from), mb_str_split($to), $str); +} + +function encodestring($st) { + $st = mb_strtr($st,"абвгдеёзийклмнопрстуфхъыэ !+-()", "abvgdeeziyklmnoprstufh_ie______"); + $st = mb_strtr($st,"АБВГДЕЁЗИЙКЛМНОПРСТУФХЪЫЭ", "ABVGDEEZIYKLMNOPRSTUFH_IE"); + $st = strtr($st, array( + " " => '_', + "." => '_', + "," => '_', + "?" => '_', + "\"" => '_', + "'" => '_', + "/" => '_', + "\\" => '_', + "%" => '_', + "#" => '_', + "*" => '_', + "ж"=>"zh", "ц"=>"ts", "ч"=>"ch", "ш"=>"sh", + "щ"=>"shch","ь"=>"", "ю"=>"yu", "я"=>"ya", + "Ж"=>"ZH", "Ц"=>"TS", "Ч"=>"CH", "Ш"=>"SH", + "Щ"=>"SHCH","Ь"=>"", "Ю"=>"YU", "Я"=>"YA", + "Й"=>"i", "й"=>"ie", "ё"=>"Ye", + "№"=>"N" + )); + return strtolower($st); +} + +function validate_encoded_string($st) { + $enc_st = encodestring($st); + return preg_match('/^[\w_-]+(\.[\w_-]+)?$/', $enc_st); +} diff --git a/core/tools/templateimage.php b/src/Tools/TemplateImage.php similarity index 98% rename from core/tools/templateimage.php rename to src/Tools/TemplateImage.php index 302678e..31bdfcc 100644 --- a/core/tools/templateimage.php +++ b/src/Tools/TemplateImage.php @@ -1,11 +1,9 @@ 'jpeg', 'gif' => 'gif', 'png' => 'png', 'bmp' => 'wbmp'); static $listfonts = array( diff --git a/src/UTF8.php b/src/UTF8.php new file mode 100644 index 0000000..3cc68b8 --- /dev/null +++ b/src/UTF8.php @@ -0,0 +1,12 @@ +get($this->field)); + } +} diff --git a/core/validator/rule/isfile.php b/src/Validator/Rule/IsFile.php similarity index 94% rename from core/validator/rule/isfile.php rename to src/Validator/Rule/IsFile.php index a2385ad..c19cf12 100644 --- a/core/validator/rule/isfile.php +++ b/src/Validator/Rule/IsFile.php @@ -1,11 +1,9 @@ field = $field; - $this->refField = $refField; - $this->errorMsg = $errorMsg; - } -*/ - public function isValid(Collection $container, $status = null) { return (strcmp($container->get($this->field), $container->get($this->same)) == 0); } diff --git a/core/validator/rule/notnull.php b/src/Validator/Rule/Notnull.php similarity index 88% rename from core/validator/rule/notnull.php rename to src/Validator/Rule/Notnull.php index 8a2170e..2b0c3cb 100644 --- a/core/validator/rule/notnull.php +++ b/src/Validator/Rule/Notnull.php @@ -1,8 +1,6 @@ ctx->isUnique($container->get($this->field), $status); + return $this->ctx->isUnique($container->get($this->field), $status, $container); } } diff --git a/core/validator/validator.php b/src/Validator/Validator.php similarity index 65% rename from core/validator/validator.php rename to src/Validator/Validator.php index 4aa9d7f..fe3ea2e 100644 --- a/core/validator/validator.php +++ b/src/Validator/Validator.php @@ -1,11 +1,11 @@ /** * Проверка коллекции */ -class Validator +class Validator_Validator { protected $chain = array(); // Массив правил protected $errorMsg = array(); // Массив ошибок @@ -23,26 +23,26 @@ class Validator public function addRuleList(array $input) { $type = array( - 'date' => 'Rule_Date', - 'email' => 'Rule_Email', - 'emaillist'=> 'Rule_EmailList', - 'match' => 'Rule_Match', - 'time' => 'Rule_Time', - 'alpha' => 'Rule_Alpha', - 'require' => 'Rule_Notnull', - 'numeric' => 'Rule_Numeric', - 'unique' => 'Rule_Unique', - 'count' => 'Rule_Count', - 'isfile' => 'Rule_IsFile', - 'code' => 'Rule_Code' + 'date' => 'Validator_Rule_Date', + 'email' => 'Validator_Rule_Email', + 'emaillist'=> 'Validator_Rule_EmailList', + 'match' => 'Validator_Rule_Match', + 'time' => 'Validator_Rule_Time', + 'alpha' => 'Validator_Rule_Alpha', + 'require' => 'Validator_Rule_Notnull', + 'numeric' => 'Validator_Rule_Numeric', + 'unique' => 'Validator_Rule_Unique', + 'filename' => 'Validator_Rule_FileName', + 'count' => 'Validator_Rule_Count', + 'isfile' => 'Validator_Rule_IsFile', + 'code' => 'Validator_Rule_Code' ); // Разбор правила проверки // Формат правила 'rule1|rule2,param1=value1|rule3,param1=value1,param2=value2' foreach ($input as $value) { // Список правил - if (!isset($value['validate']) || $value['validate'] == '') continue; - + if (! isset($value['validate'])) continue; $rules = explode("|", $value['validate']); foreach ($rules as $rule) { // Список параметров правила @@ -50,17 +50,17 @@ class Validator $name = array_shift($rule_param); if (isset($type[$name])) { - $constructor = $type[$name]; // "Rule_" . ucfirst($name) - $rule = new $constructor($value['name'], false); // Нужны шаблонные сообщения для правил + $constructor = $type[$name]; + $ruleObj = new $constructor($value['name'], false); // Нужны шаблонные сообщения для правил if (isset($value['context'])) { - $rule->setContext($value['context']); + $ruleObj->setContext($value['context']); } foreach ($rule_param as $param) { // Имя и значение параметра - list($name, $value) = explode("=", $param); - $rule->$name = $value; + list($p_name, $p_value) = explode("=", $param); + $ruleObj->$p_name = $p_value; } - $this->addRule($rule); + $this->addRule($ruleObj); } else { throw new Exception('Unknown validation rule "' . $rule . "'"); } @@ -68,8 +68,7 @@ class Validator } } - public function addRule(&$rule) - { + public function addRule(/*.any.*/&$rule) { if (is_array($rule)) { $this->chain = array_merge($this->chain, $rule); } else { @@ -91,14 +90,17 @@ class Validator public function validate(Collection $container, $rule = null, $status = null) { + $fields = array(); if ($rule) { $this->chain = $rule; } $this->errorMsg = array(); - foreach ($this->chain as $key => $rule) { - if (!$this->skip($rule, $container) && !$rule->isValid($container, $status)) { + foreach ($this->chain as $rule) { + //echo $key; + if (!in_array($rule->field, $fields) && !$this->skip($rule, $container) && !$rule->isValid($container, $status)) { $name = $rule->field; $this->errorMsg[$name] = $rule->getErrorMsg(); + $fields [] = $name; } } return $this->isValid(); diff --git a/src/View/Composite.php b/src/View/Composite.php new file mode 100644 index 0000000..0a21508 --- /dev/null +++ b/src/View/Composite.php @@ -0,0 +1,41 @@ +tal = new PHPTAL($file); + $this->tal->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION); + $this->tal->setEncoding(PHPTAL_DEFAULT_ENCODING); // PHPTAL_DEFAULT_ENCODING !! + $this->tal->setTemplateRepository(PHPTAL_TEMPLATE_REPOSITORY); + $this->tal->setOutputMode(PHPTAL::HTML5); + $this->tal->stripComments(true); +// $this->tal->addPreFilter(new PHPTAL_PreFilter_Normalize()); + } + + function set($key, $val) { + if ($key == 'title') { + $this->setTitle($val); + } + $this->tal->set($key, $val); + } + + function __set($key, $val) { + $this->tal->set($key, $val); + } + + function execute() + { + parent::execute(); + // postProcess + return $this->tal->execute(); + } +} diff --git a/src/View/Page.php b/src/View/Page.php new file mode 100644 index 0000000..acddc60 --- /dev/null +++ b/src/View/Page.php @@ -0,0 +1,73 @@ +]*>/u'; + $matches = array(); + preg_match_all($pattern, $data, $matches, PREG_OFFSET_CAPTURE, 0); + + $split = array(); + $offset = 0; + foreach ($matches[0] as $key => $match) { + $text = $this->fixHTML(substr($data, $offset, $match[1] - $offset)); + if (trim($text)) { + $split[] = array('type' => 'page-text', 'content' => $text, 'component' => '', 'module' => ''); + } + $offset = $match[1] + strlen($match[0]); + $split[] = $this->replaceContent($matches[3][$key][0], $matches[3][$key][1]); + } + $text = $this->fixHTML(substr($data, $offset)); + if (trim($text)) { + $split[] = array('type' => 'page-text', 'content' => $text, 'component' => '', 'module' => ''); + } + + $this->text = $this->merge($split); + } + + function fixHTML($fragment) { + return $fragment; + } + + function merge($data) { + if (count($data) == 0) { + $data[] = array('type' => 'page-text', 'content' =>"

Добавьте текст

", 'component' => '', 'module' => ''); + } + $result = array(); + foreach($data as $key => $part) { + $result[] = $part['content']; + } + return implode("", $result); + } + + function replaceContent($match, $offset) + { + //$result = phptal_component($match, $offset); + + //* + global $db, $registry; // Нужно как-то передавать параметры + + $component = Controller_Component::loadComponent($match, $db, $registry); + $req = new HttpRequest(); + unset($req['active_page']); + + $info = $component->getInfo(); + $result = $component->execute($req); + + if (is_string($result)) { + return array('type' => 'page-component', 'content' => $result, 'component' => $match); + } else { + $this->setView('view' . $this->counter++, $result); + return array('type' => 'page-component', 'content' => $result->execute(), 'component' => $match); + } + } + + function execute() { + return $this->text; + } +} diff --git a/core/view/view.php b/src/View/Plain.php similarity index 72% rename from core/view/view.php rename to src/View/Plain.php index bacc54e..67d4521 100644 --- a/core/view/view.php +++ b/src/View/Plain.php @@ -3,10 +3,13 @@ // Класс отображения // CompositeView !! Composite pattern -class View +/** + * @package system.view + */ +class View_Plain { protected $document; - protected $values; + protected $values = array(); public function __construct ($document) { @@ -18,6 +21,11 @@ class View $this->values[$key] = $value; } + public function import($list) + { + $this->values = array_merge($this->values, $list); + } + public function __set($key, $value) { $this->set($key, $value); @@ -33,8 +41,8 @@ class View { ob_start (); include ($document); - $result = ob_get_contents (); + $content = ob_get_contents (); ob_clean (); - return $result; + return $content; } } diff --git a/src/View/Top.php b/src/View/Top.php new file mode 100644 index 0000000..95bbff5 --- /dev/null +++ b/src/View/Top.php @@ -0,0 +1,174 @@ +doTree('_title', false), array($this, 'isNotNull'))); + } + + private function findGroup($groups, $file) + { + foreach($groups as $key => $group) { + if(in_array($file, $group)) { + return $key; + } + } + return false; + } + + private function groupFiles(array $list, $debug = true) + { + $debug = ($debug) ? 'debug=1' : ''; + $path = parse_url(WWW_PATH, PHP_URL_PATH); + // Группы определять в import через , + $groups = array( ); + $use = array(); + + $result = array(); + foreach ($list as $file) { + $name = $this->findGroup($groups, $file); + if($name) { + $use [$name] = 1; + } else { + if (strpos($file, 'ckeditor')) { + $result [] = $file; + } else { +// $result [] = WWW_PATH . "/min/?$debug&f=" . parse_url($file, PHP_URL_PATH); + $result [] = $file; + } + } + } + $list = array(); + foreach ($use as $name => $value) { +// $list [] = WWW_PATH . "/min/?$debug&f=" . implode(",", $groups[$name]); + $list [] = $groups[$name]; + } + + return array_merge($list, $result); + } + + + function getId($pref) { + $this->mid++; + return $pref.$this->mid; + } + + /** + * Обработка шаблона + * + * @return string + */ + public function render() + { + + $alias = $this->doTree('alias'); + +// require_once 'minify.php'; + // Скрипты и стили + $this->set('scriptstring', $this->getScriptRaw()); + $this->set('scripts', array_unique($this->groupFiles($this->getScripts(), false))); + $this->set('stylesheet', array_unique($this->groupFiles($this->getStyleSheet(), false))); + + $this->require = array('admin' => 'ma'); + $this->deps = array(); + + $startup = array(); + foreach($this->_section as $s) { + $module = explode('_', $s->active_module, 2); + if (count($module) < 2) { + continue; + } + + $module = $module[1]; + + $name = mb_strtolower($module); + $fname = $name . '/' . $name; + + $current = $this->getId('m'); + $this->require[$fname] = $current; + + $value = $this->getId('v'); + + $script = "var " . $value . " = new " . $current . '.' . $module . "();\n"; + foreach($s->_values as $key => $v) { + $script .= $value . "." . $key . " = " . json_encode($v/*, JSON_PRETTY_PRINT*/) . ";\n"; + } + + $init = array(); + foreach($s->_section as $key => $item) { + /*.View_View.*/$ss = $item; + if ($ss->codeGenerator !== null) { + // функцию которая вычисляет а не результат + $part = call_user_func($ss->codeGenerator, $this, $key, $value); + $init [] = $part; + } + } + + $script .= $value . ".execute('" . $s->module_action . "', " . json_encode($init) .");\n"; + $startup[] = $script; + + } + + +/* echo "

";
+		print_r($this->require);
+		print_r(implode("", $startup));
+		echo "
";*/ + + //$this->set('scriptstring', ''); + $this->set('startup', implode("", $startup) . $this->getScriptStartup()); + + + $this->set('require', implode(",", array_map(function ($x) { return "'$x'";}, array_keys($this->require)))); + $this->set('deps', implode(",", array_values($this->require))); + + + $this->set('title', $this->getTitle()); + $this->set('jspath', WWW_PATH); + // + return $this->execute(); // execute+phptal ?? + } + + /** + * Массив имен файлов скриптов + * + * return array + */ + public function getScripts() + { + return $this->doTree('_script'); + } + + /** + * Строка со скриптом + * + * @return string + */ + public function getScriptRaw() + { + return implode("\n", $this->doTree('_scriptstring')); + } + + public function getScriptStartup() + { + return implode("\n", $this->doTree('_startup')); + } + + /** + * Массив имен файлов стилей + * + * return array + */ + public function getStyleSheet() + { + return $this->doTree('_stylesheet'); + } + +} diff --git a/src/View/View.php b/src/View/View.php new file mode 100644 index 0000000..cd51d8b --- /dev/null +++ b/src/View/View.php @@ -0,0 +1,203 @@ + View_Base + View_List + View_Template +class View_View +{ + protected $_section = array(); // Вложенные шаблоны + // Блоки + protected $_stylesheet = array(); // Массив стилей текущего шаблона + protected $_script = array(); // Массив скриптов текущего шаблона + protected $_scriptstring = array(); + protected $_startup = array(); + protected $_values = array(); + + protected $_title = null; // Заголовок текущего шаблона + + public $active_module; + public $module_action; + + public $suggestions; //подсказки + + public $alias = array(); + public $codeGenerator = null; + public $parent_view = null; + + function __construct() { + } + + /** + * Связывет переменную с вложенным шаблоном + * + * @param string $section переменная шаблона + * @param CompositeView $view вложенный шаблон + */ + public function setView($section, View_View $view) + { + $this->_section [$section] = $view; + $view->parent_view = $this; + } + + public function assignValues($values) + { + $this->_values = $values; + $this->_values["suggestions"] = $this->suggestions; + } + + public function jGrowl($message, $args) + { + $this->addScriptRaw('$.jGrowl("' . $message . '", ' . json_encode($args) . ");\n", true); + } + + public function setGlobal($name, $args) + { + $this->addScriptRaw("var " . $name . " = " . json_encode($args) . ";\n", false); + } + + /** + * Добавляет скипт к текущему шаблону + * + * @param string $name путь к скрипту + */ + public function addScript($name) + { + $output = $this->resolveName($this->alias, $name); + $this->_script [] = $output; + } + + /** + * Добавляет код скипта к текущему шаблону + * + * @param string $name строка javascript кода + */ + public function addScriptRaw($name, $startup = false) + { + if ($startup) { + $this->_startup [] = $name; + } else { + $this->_scriptstring [] = $name; + } + } + + /** + * Добавляет стили к текущему шаблону + * + * @param string $name путь к стилю + */ + public function addStyleSheet($name) + { + $output = $this->resolveName($this->alias, $name); + $this->_stylesheet [] = $output; + } + + /** + * Рекурсивно извлекает из значение свойства обьекта + * + * @param string $list Имя свойства + * @param boolean $flatten + */ + protected function doTree($list, $flatten = true) + { + $result = ($flatten == true) ? $this->$list : array($this->$list); + foreach ($this->_section as $value) { + if (is_object($value)) { + if ($list == '_script' || $list == '_stylesheet') { + $result = array_merge($result, $value->doTree($list, $flatten)); + } else { + $result = array_merge($value->doTree($list, $flatten), $result); + } + } + } + return $result; + } + + /*abstract*/ public function set($key, $value) + { + } + + /** + * Обработка всех вложенных шаблонов + * + * @return string + */ + public function execute() + { + foreach ($this->_section as $key => $value) { + $this->set($key, (is_object($value)) ? $value->execute() : $value); // ? + } + } + + /** + * Установка заголовка шаблона + * + * @param string $title + */ + public function setTitle($title) + { + $this->_title = $title; + } + + protected function isNotNull($title) + { + return $title !== null; + } + + function setAlias($alias) + { + $this->alias = $alias; + } + + function addAlias($name, $path) + { + $this->alias[$name] = $path; + $this->set($name, $path); + } + + function find_file($pathlist, $file) { + foreach($pathlist as $key => $www) { + if (file_exists($key . '/' . $file)) { + return $www . '/' . $file; + } + } + throw new Exception("file not found: $file"); + } + + function resolveName($alias, $file) { + list($type, $filename) = explode(":", $file, 2); + + // Сделать поиск а не просто замену папки при совпадении имени + if (is_array($alias[$type])) { + $output = $this->find_file($alias[$type], $filename); + } else { + $output = $alias[$type] . '/' . $filename; + } + return $output; + } + + function loadImports($importFile) + { + $types = array( + 'js' => array($this, 'addScript'), + 'css' => array($this, 'addStyleSheet') + ); + // Подключение стилей и скриптов + if (file_exists($importFile)) { + $files = file($importFile); + foreach ($files as $file) { + // Получить расширение вместо strpos + $file = trim($file); + if (!empty($file)) { + $ext = pathinfo($file, PATHINFO_EXTENSION); + call_user_func($types[$ext], $file); + } + } + } + } + + public function resolveAllNames($alias, $list) { + $result = array(); + foreach($list as $item) { + $result [] = $this->resolveName($alias, $item); + } + return $result; + } +} \ No newline at end of file diff --git a/src/View/list.php b/src/View/list.php new file mode 100644 index 0000000..8522b32 --- /dev/null +++ b/src/View/list.php @@ -0,0 +1,13 @@ +_section as $key => $value) { + $result [] = $value->execute(); + } + return $result; + } +} diff --git a/core/zipfile.php b/src/ZipFile.php similarity index 75% rename from core/zipfile.php rename to src/ZipFile.php index e55c100..49c4ddd 100644 --- a/core/zipfile.php +++ b/src/ZipFile.php @@ -5,21 +5,28 @@ */ class ZipFile extends ZipArchive { + private $ignore = array('.', '..'); + + public function addIgnore($name) + { + $this->ignore [] = $name; + } + private function addDirDo($location, $name) { assert(is_string($location) && is_string($name)); $name .= '/'; $location .= '/'; + $file = null; // Read all Files in Dir $dir = opendir($location); while (($file = readdir($dir)) !== false) { - if ($file === '.' || $file === '..') continue; - + if (in_array($file, $this->ignore)) continue; // Rekursiv, If dir: FlxZipArchive::addDir(), else ::File(); - $call = (is_dir($file)) ? 'addDir' : 'addFile'; + $call = (is_dir($location . $file)) ? 'addDir' : 'addFile'; call_user_func(array($this, $call), $location . $file, $name . $file); } } diff --git a/core/config.php b/src/config.php similarity index 100% rename from core/config.php rename to src/config.php diff --git a/core/functions.php b/src/functions.php similarity index 83% rename from core/functions.php rename to src/functions.php index f3bd521..e9ae380 100644 --- a/core/functions.php +++ b/src/functions.php @@ -107,7 +107,7 @@ function compose() { * * @return array[int]mixed */ -function rcurry() { +function rcurry($_rest) { $closure = new __right(func_get_args ()); return array($closure, 'apply'); } @@ -117,7 +117,7 @@ function rcurry() { * * @return array[int]mixed */ -function lcurry() { +function lcurry($_rest) { $closure = new __left(func_get_args ()); return array($closure, 'apply'); } @@ -192,7 +192,7 @@ function __self($name, $o) { function concat(/* $args ...*/) { $args = func_get_args(); - return implode($args); + return implode("", $args); } function __empty($x) { @@ -229,6 +229,15 @@ function key_values($key, /*array|ArrayIterator*/ $array) { return $result; } +function key_values_object($key, /*array|ArrayIterator*/ $array) { + $result = array(); + + foreach($array as $item) { + $result[] = $item->{$key}; + } + return $result; +} + function assoc_key_values($key, $value, $array) { $result = array(); foreach ($array as $item) { @@ -245,7 +254,7 @@ function assoc_key($key, $array) { return $result; } -function _get($key, $value, $array) { +function _get($key, /*.any.*/$value, /*.array.*/$array) { foreach ($array as $item) { if ($item[$key] == $value) return $item; } @@ -265,7 +274,7 @@ function _get_key($key, $value, $array) { * @return bool */ function every(array $array, $callback) { - foreach ($array as $key => $value) { + foreach ($array as $value) { if (call_user_func($callback, $value) === false) { return false; } @@ -337,10 +346,33 @@ if (!function_exists('hash_key')) { }; } -function array_merge1($x, $y) { - $result = $x; - foreach ($y as $k => $v) { - $result [$k] = $v; +/** + * Выбирает все сроки из таблицы с уникальными значениями ключа + * @param $name Имя ключа + * @param $table Двухмерный массив + * @example + * key_unique_values ('name', array (array ('name' => 1), array ('name' => 2), array ('name' => 1))) + => array (1, 2) + * @end example + */ +function key_unique_values ($name, $table) { + // Ищем уникальные значения для заданного ключа + $keys = array (); + foreach ($table as $row) { + if (!in_array ($row[$name], $keys)) + $keys[] = $row[$name]; } - return $result; + return $keys; +} + +/** + * Сортировка двумерного массива по заданному ключу + * @param $array Массив + * @param $key Имя ключа по значению которого будет идти сравнение + * @return Отсортированный массив + */ +function sortOn($array, $key, $fn = '__cmp') { + usort ($array, rcurry($fn, $key)); + //usort ($array, create_function ('$x,$y', 'return __cmp ($x, $y, "'.$key.'");')); + return $array; } diff --git a/src/process.php b/src/process.php new file mode 100644 index 0000000..c32c284 --- /dev/null +++ b/src/process.php @@ -0,0 +1,41 @@ +execute($req); + + echo ""; + return $result; +} + + +/* Регистрация нового префикса для подключения компонента */ +$tales = PHPTAL_TalesRegistry::getInstance(); +$tales->registerPrefix('component', array('Component_Tales', 'component')); +$tales->registerPrefix('date', array('DateTime_Tales', 'date')); +$tales->registerPrefix('time', array('DateTime_Tales', 'time')); +