Path: blob/master/src/infrastructure/util/PhabricatorSlug.php
12241 views
<?php12final class PhabricatorSlug extends Phobject {34public static function normalizeProjectSlug($slug) {5$slug = str_replace('/', ' ', $slug);6$slug = self::normalize($slug, $hashtag = true);7return rtrim($slug, '/');8}910public static function isValidProjectSlug($slug) {11$slug = self::normalizeProjectSlug($slug);12return ($slug != '_');13}1415public static function normalize($slug, $hashtag = false) {16$slug = preg_replace('@/+@', '/', $slug);17$slug = trim($slug, '/');18$slug = phutil_utf8_strtolower($slug);1920$ban =21// Ban control characters since users can't type them and they create22// various other problems with parsing and rendering.23"\\x00-\\x19".2425// Ban characters with special meanings in URIs (and spaces), since we26// want slugs to produce nice URIs.27"#%&+=?".28" ".2930// Ban backslashes and various brackets for parsing and URI quality.31"\\\\".32"<>{}\\[\\]".3334// Ban single and double quotes since they can mess up URIs.35"'".36'"';3738// In hashtag mode (used for Project hashtags), ban additional characters39// which cause parsing problems.40if ($hashtag) {41$ban .= '`~!@$^*,:;(|)';42}4344$slug = preg_replace('(['.$ban.']+)', '_', $slug);45$slug = preg_replace('@_+@', '_', $slug);4647$parts = explode('/', $slug);4849// Remove leading and trailing underscores from each component, if the50// component has not been reduced to a single underscore. For example, "a?"51// converts to "a", but "??" converts to "_".52foreach ($parts as $key => $part) {53if ($part != '_') {54$parts[$key] = trim($part, '_');55}56}57$slug = implode('/', $parts);5859// Specifically rewrite these slugs. It's OK to have a slug like "a..b",60// but not a slug which is only "..".6162// NOTE: These are explicitly not pht()'d, because they should be stable63// across languages.6465$replace = array(66'.' => 'dot',67'..' => 'dotdot',68);6970foreach ($replace as $pattern => $replacement) {71$pattern = preg_quote($pattern, '@');72$slug = preg_replace(73'@(^|/)'.$pattern.'(\z|/)@',74'\1'.$replacement.'\2', $slug);75}7677return $slug.'/';78}7980public static function getDefaultTitle($slug) {81$parts = explode('/', trim($slug, '/'));82$default_title = end($parts);83$default_title = str_replace('_', ' ', $default_title);84$default_title = phutil_utf8_ucwords($default_title);85$default_title = nonempty($default_title, pht('Untitled Document'));86return $default_title;87}8889public static function getAncestry($slug) {90$slug = self::normalize($slug);9192if ($slug == '/') {93return array();94}9596$ancestors = array(97'/',98);99100$slug = explode('/', $slug);101array_pop($slug);102array_pop($slug);103104$accumulate = '';105foreach ($slug as $part) {106$accumulate .= $part.'/';107$ancestors[] = $accumulate;108}109110return $ancestors;111}112113public static function getDepth($slug) {114$slug = self::normalize($slug);115if ($slug == '/') {116return 0;117} else {118return substr_count($slug, '/');119}120}121122}123124125