'', 'ai1ec' => array(), 'args' => null, 'hash' => null, '_type' => 'args', // enum: args,hash,pretty ); if ( false === ( $parsed = parse_url( $page ) ) ) { return false; } if ( isset( $parsed['scheme'] ) ) { if ( !isset( $parsed['host'] ) ) { return false; } $result['base'] = $parsed['scheme'] . '://' . $parsed['host']; } if ( ! empty( $parsed['path'] ) ) { if ( false !== strpos( $parsed['path'], self::DIRECTION_SEPARATOR ) ) { $result['_type'] = 'pretty'; $elements = explode( $this->_arguments_separator, $parsed['path'] ); foreach ( $elements as $particle ) { $sep = strpos( $particle, self::DIRECTION_SEPARATOR ); if ( false !== $sep ) { $key = substr( $particle, 0, $sep ); $result['ai1ec'][$key] = substr( $particle, $sep + 1 ); } else { $result['base'] .= $this->_arguments_separator . $particle; } } } } $query_pos = array( 'query' => 'args', 'fragment' => 'hash', ); foreach ( $query_pos as $source => $destination ) { if ( 'hash' === $destination ) { $result['_type'] = $destination; } if ( ! empty( $parsed[$source] ) ) { $result = Ai1ec_Utility_Array::deep_merge( $result, $this->parse_query_str( $parsed[$source], $destination ) ); } } return $result; } /** * Produce query to use in URI * * @param array $parsed Internal query representation * * @return string Normalized URI */ public function write( array $parsed ) { $uri = $parsed['base']; if ( 'pretty' == $parsed['_type'] ) { $uri = rtrim( $uri, $this->_arguments_separator ); foreach ( $parsed['ai1ec'] as $key => $value ) { $uri .= $this->_arguments_separator . $this->_clean_key( $key ) . self::DIRECTION_SEPARATOR . $this->_safe_uri_value( $value ); } } else { $place = $parsed['_type']; $action = isset( $parsed['ai1ec']['action'] ) ? $parsed['ai1ec']['action'] : NULL; if ( empty( $action ) ) { foreach ( array( 'args', 'hash' ) as $place ) { if ( ! empty( $parsed[$place]['action'] ) ) { $action = $parsed[$place]['action']; break; } } } if ( empty( $action ) ) { $action = 'uri_err'; } if ( 0 !== strncmp( $action, 'ai1ec_', 6 ) ) { $action = 'ai1ec_' . $action; } $combined_ai1ec = array(); foreach ( $parsed['ai1ec'] as $key => $value ) { $combined_ai1ec[] = $this->_clean_key( $key ) . self::DIRECTION_SEPARATOR . $this->_safe_uri_value( $value ); } $combined_ai1ec = implode( '|', $combined_ai1ec ); $parsed[$place]['ai1ec'] = $combined_ai1ec; if ( 'hash' === $place ) { $parsed[$place]['action'] = $action; } unset( $combined_ai1ec, $place ); } $arg_list = array( 'args' => '?', 'hash' => '#', ); foreach ( $arg_list as $name => $separator ) { if ( ! empty( $parsed[$name] ) ) { $uri .= $separator . build_query( $parsed[$name] ); } } return $uri; } /** * Convert query string to internal representation * * @param string $query Query to parse * @param string $name Positional name (i.e. 'hash') * * @return array Parsed query map with 'ai1ec' and {$name} keys */ public function parse_query_str( $query, $name ) { $result = array( 'ai1ec' => array(), $name => array(), ); $parsed = null; parse_str( $query, $parsed ); foreach ( $parsed as $key => $value ) { if ( 0 === strncmp( $key, 'ai1ec', 5 ) ) { $result['_type'] = $name; if ( ! is_array( $value ) ) { if ( 'ai1ec' === $key ) { $value_list = explode( '|', $value ); $value = array(); foreach ( $value_list as $entry ) { list( $sub_key, $sub_value ) = explode( self::DIRECTION_SEPARATOR, $entry ); $value[$sub_key] = $sub_value; } unset( $value_list ); } else { $value = array( substr($key, 6) => $value ); } } $result['ai1ec'] = array_merge( $result['ai1ec'], $value ); } else { $result[$name][$key] = $value; } } unset( $parsed ); return $result; } /** * Create URI-safe value (scalar) * * @param mixed $value Value provided for URL * * @return string Value to use in URI */ protected function _safe_uri_value( $value ) { if ( is_array( $value ) ) { $value = implode(',', $value); } return $value; } /** * Clean AI1EC sub-element key * * @param string $key Key to clean * * @return string Cleaned key to output */ protected function _clean_key( $key ) { if ( 0 === strncmp( $key, 'ai1ec_', 6 ) ) { $key = substr( $key, 6 ); } return $key; } }