Last active
December 28, 2022 23:30
-
-
Save florianbrinkmann/9fae1f1003f33955fecb2735e02ffd96 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Needs php_mbstring extension | |
*/ | |
ini_set( 'memory_limit', '1024M' ); | |
date_default_timezone_set( 'UTC' ); | |
// Damit es in der Konsole nicht so lange dauert | |
error_reporting( 0 ); | |
// <load users file> | |
$users = json_decode( file_get_contents( __DIR__ . '/' . 'users.json' ), true ); | |
$usersById = array(); | |
foreach ( $users as $user ) { | |
$usersById[ $user['id'] ] = $user; | |
} | |
// </load users file> | |
// <load channels file> | |
$channels = json_decode( file_get_contents( __DIR__ . '/' . 'channels.json' ), true ); | |
$channelsById = array(); | |
foreach ( $channels as $channel ) { | |
$channelsById[ $channel['id'] ] = $channel; | |
} | |
/** | |
* with $_GET['start-date'] and $_GET['end-date'] you can set a range of days for the xml | |
* or, on the command line: php slack-to-xml.php start-date="01.01.2016" end-date="05.01.2016" | |
* you can also set either start-date or end-date | |
*/ | |
$args = $argv; | |
$start_date_arg = preg_grep( '/start-date=/', $args ); | |
$end_date_arg = preg_grep( '/end-date=/', $args ); | |
$start_date_timestamp = ''; | |
if ( ! empty( $start_date_arg ) ) { | |
$start_date_arg = end( $start_date_arg ); | |
$start_date = preg_replace( '/start-date=/', '', $start_date_arg ); | |
$start_date_timestamp = strtotime( $start_date ); | |
} elseif ( isset( $_GET['start-date'] ) ) { | |
$start_date_timestamp = strtotime( $_GET['start-date'] ); | |
} | |
$end_date_timestamp = ''; | |
if ( ! empty( $end_date_arg ) ) { | |
$end_date_arg = end( $end_date_arg ); | |
$end_date = preg_replace( '/end-date=/', '', $end_date_arg ); | |
$end_date_timestamp = strtotime( $end_date ); | |
} elseif ( isset( $_GET['end-date'] ) ) { | |
$end_date_timestamp = strtotime( $_GET['end-date'] ); | |
} | |
// </load channels file> | |
$files = scandir( __DIR__ ); | |
$xml_export_array = [ ]; | |
foreach ( $files as $channel ) { | |
if ( $channel == '.' || $channel == '..' ) { | |
continue; | |
} | |
if ( is_dir( $channel ) ) { | |
unset( $chats ); | |
$chats = array(); | |
$dates = scandir( __DIR__ . '/' . $channel ); | |
foreach ( $dates as $date ) { | |
if ( ! is_dir( $date ) ) { | |
$messages = json_decode( file_get_contents( __DIR__ . '/' . $channel . '/' . $date ), true ); | |
$pattern = '/([0-9\-]+)/'; | |
preg_match( $pattern, $date, $match ); | |
if ( ! empty( $match ) ) { | |
$date = $match[0]; | |
$date_timestamp = strtotime( $date ); | |
if ( ( $start_date_timestamp != "" && $start_date_timestamp > $date_timestamp ) ) { | |
continue; | |
} | |
if ( $end_date_timestamp != "" && $end_date_timestamp < $date_timestamp ) { | |
continue; | |
} | |
} | |
if ( empty( $messages ) ) { | |
continue; | |
} | |
foreach ( $messages as $message ) { | |
if ( empty( $message ) ) { | |
continue; | |
} | |
if ( empty( $message['text'] ) ) { | |
continue; | |
} | |
// change <@U38A3DE9> into levelsio | |
if ( stripos( $message['text'], '<@' ) !== false ) { | |
$usersInMessage = explode( '<@', $message['text'] ); | |
foreach ( $usersInMessage as $userInMessage ) { | |
$array = explode( '>', $userInMessage ); | |
$userHandleInBrackets = $array[0]; | |
$array = explode( '|', $array[0] ); | |
$userInMessage = $array[0]; | |
$username = $array[1]; | |
if ( empty( $username ) ) { | |
$username = $usersById[ $userInMessage ]['name']; | |
} | |
$message['text'] = str_replace( '<@' . $userHandleInBrackets . '>', '@' . $username, $message['text'] ); | |
} | |
} | |
// change <#U38A3DE9> into #_chiang-mai | |
if ( stripos( $message['text'], '<#' ) !== false ) { | |
$channelsInMessage = explode( '<#', $message['text'] ); | |
foreach ( $channelsInMessage as $channelInMessage ) { | |
$array = explode( '>', $channelInMessage ); | |
$channelHandleInBrackets = $array[0]; | |
$array = explode( '|', $array[0] ); | |
$channelInMessage = $array[0]; | |
if ( ! empty ( $array[1] ) ) { | |
$channelNameInMessage = $array[1]; | |
} | |
if ( empty( $channelNameInMessage ) ) { | |
if ( ! empty( $channelsById[ $channelInMessage ]['name'] ) ) { | |
$channelNameInMessage = $channelsById[ $channelInMessage ]['name']; | |
} | |
} | |
$message['text'] = str_replace( '<#' . $channelHandleInBrackets . '>', '#' . $channelNameInMessage, $message['text'] ); | |
} | |
} | |
// change <http://url> into link | |
if ( stripos( $message['text'], '<http' ) !== false ) { | |
$linksInMessage = explode( '<http', $message['text'] ); | |
foreach ( $linksInMessage as $linkInMessage ) { | |
$array = explode( '>', $linkInMessage ); | |
$linkTotalInBrackets = $array[0]; | |
if ( stripos($linkTotalInBrackets, '|')) { | |
$array = explode( '|', $array[0] ); | |
$linkInMessage = $array[0]; | |
$message['text'] = str_replace( '<http' . $linkTotalInBrackets . '>', '<http' . $linkInMessage . '>', $message['text'] ); | |
} | |
} | |
} | |
// change @here et cetera so that it doesn’t get converted to a mailto:link from the markdown parser | |
if ( stripos( $message['text'], '<!' ) !== false ) { | |
$mentionsInMessage = explode( '<!', $message['text'] ); | |
foreach ( $mentionsInMessage as $mentionInMessage ) { | |
$array = explode( '>', $mentionInMessage ); | |
$mentionInBrackets = $array[0]; | |
if ( stripos($mentionInBrackets, '|')) { | |
$array = explode( '|', $array[0] ); | |
$mentionInMessage = $array[0]; | |
$mention = $array[1]; | |
$message['text'] = str_replace( '<!' . $mentionInBrackets . '>',$mention, $message['text'] ); | |
} | |
} | |
} | |
$array = explode( '.', $message['ts'] ); | |
$message_timestamp = $message['ts']; | |
$message_date = date( 'd.m.Y H:i', $message_timestamp ); | |
if ( ! empty ( $message['user'] ) ) { | |
$gravatar = $usersById[ $message['user'] ]['profile']['image_72']; | |
} | |
if ( ! empty ( $message['user'] ) ) { | |
$username = $usersById[ $message['user'] ]['name']; | |
} | |
$message = $message['text']; | |
// replace > on line start with > so that the markdown parser | |
// creates a blockquote | |
$pattern = '/^>/m'; | |
preg_match_all($pattern, $message, $match); | |
if ( ! empty($match)) { | |
$message = preg_replace($pattern, '>', $message); | |
} | |
/** | |
* Input line break after > so that this: | |
* | |
* > Test | |
* Reaction | |
* | |
* is not parsed as blockquote but only > Test | |
*/ | |
$pattern = '/(^>.*(\n){1})^[^>]/m'; | |
preg_match_all($pattern, $message, $matches); | |
if ( ! empty($matches)) { | |
foreach ($matches as $key => $match ) { | |
if ( $key == 1 && ! empty($match) ) { | |
foreach ( $match as $match_string ) { | |
$message = str_replace($match_string, $match_string . "\n", $message); | |
} | |
} | |
} | |
} | |
// Markdown parsen | |
$Parsedown = new Parsedown(); | |
$Parsedown->setBreaksEnabled(true); | |
$message = $Parsedown->text($message); | |
// Emojis einsetzen | |
/** | |
* EMOJI SHORT NAME’S TO HTML HEX CODE | |
* @source https://github.com/davidsword/emoji-shortname-to-hex | |
*/ | |
$emoji_unicode=array('copyright'=>'©;','registered'=>'®;','bangbang'=>'‼;','interrobang'=>'⁉;','tm'=>'™;','information_source'=>'ℹ;','left_right_arrow'=>'↔;','arrow_up_down'=>'↕;','arrow_upper_left'=>'↖;','arrow_upper_right'=>'↗','arrow_lower_right'=>'↘','arrow_lower_left'=>'↙','leftwards_arrow_with_hook'=>'↩','arrow_right_hook'=>'↪','watch'=>'⌚','hourglass'=>'⌛','keyboard'=>'⌨','eject'=>'⏏','fast_forward'=>'⏩','rewind'=>'⏪','arrow_double_up'=>'⏫','arrow_double_down'=>'⏬','black_right_pointing_double_triangle_with_vertical_bar'=>'⏭','black_left_pointing_double_triangle_with_vertical_bar'=>'⏮','black_right_pointing_triangle_with_double_vertical_bar'=>'⏯','alarm_clock'=>'⏰','stopwatch'=>'⏱','timer_clock'=>'⏲','hourglass_flowing_sand'=>'⏳','double_vertical_bar'=>'⏸','black_square_for_stop'=>'⏹','black_circle_for_record'=>'⏺','m'=>'Ⓜ','black_small_square'=>'▪','white_small_square'=>'▫','arrow_forward'=>'▶','arrow_backward'=>'◀','white_medium_square'=>'◻','black_medium_square'=>'◼','white_medium_small_square'=>'◽','black_medium_small_square'=>'◾','sunny'=>'☀','cloud'=>'☁','umbrella'=>'☂','snowman'=>'☃','comet'=>'☄','phone'=>'☎','telephone'=>'☎','ballot_box_with_check'=>'☑','umbrella_with_rain_drops'=>'☔','coffee'=>'☕','shamrock'=>'☘','point_up'=>'☝','skull_and_crossbones'=>'☠','radioactive_sign'=>'☢','biohazard_sign'=>'☣','orthodox_cross'=>'☦','star_and_crescent'=>'☪','peace_symbol'=>'☮','yin_yang'=>'☯','wheel_of_dharma'=>'☸','white_frowning_face'=>'☹','relaxed'=>'☺','aries'=>'♈','taurus'=>'♉','gemini'=>'♊','cancer'=>'♋','leo'=>'♌','virgo'=>'♍','libra'=>'♎','scorpius'=>'♏','sagittarius'=>'♐','capricorn'=>'♑','aquarius'=>'♒','pisces'=>'♓','spades'=>'♠','clubs'=>'♣','hearts'=>'♥','diamonds'=>'♦','hotsprings'=>'♨','recycle'=>'♻','wheelchair'=>'♿','hammer_and_pick'=>'⚒','anchor'=>'⚓','crossed_swords'=>'⚔','scales'=>'⚖','alembic'=>'⚗','gear'=>'⚙','atom_symbol'=>'⚛','fleur_de_lis'=>'⚜','warning'=>'⚠','zap'=>'⚡','white_circle'=>'⚪','black_circle'=>'⚫','coffin'=>'⚰','funeral_urn'=>'⚱','soccer'=>'⚽','baseball'=>'⚾','snowman_without_snow'=>'⛄','partly_sunny'=>'⛅','thunder_cloud_and_rain'=>'⛈','ophiuchus'=>'⛎','pick'=>'⛏','helmet_with_white_cross'=>'⛑','chains'=>'⛓','no_entry'=>'⛔','shinto_shrine'=>'⛩','church'=>'⛪','mountain'=>'⛰','umbrella_on_ground'=>'⛱','fountain'=>'⛲','golf'=>'⛳','ferry'=>'⛴','boat'=>'⛵','sailboat'=>'⛵','skier'=>'⛷','ice_skate'=>'⛸','person_with_ball'=>'⛹','tent'=>'⛺','fuelpump'=>'⛽','scissors'=>'✂','white_check_mark'=>'✅','airplane'=>'✈','email'=>'✉','envelope'=>'✉','fist'=>'✊','hand'=>'✋','raised_hand'=>'✋','v'=>'✌','writing_hand'=>'✍','pencil2'=>'✏','black_nib'=>'✒','heavy_check_mark'=>'✔','heavy_multiplication_x'=>'✖','latin_cross'=>'✝','star_of_david'=>'✡','sparkles'=>'✨','eight_spoked_asterisk'=>'✳','eight_pointed_black_star'=>'✴','snowflake'=>'❄','sparkle'=>'❇','x'=>'❌','negative_squared_cross_mark'=>'❎','question'=>'❓','grey_question'=>'❔','grey_exclamation'=>'❕','exclamation'=>'❗','heavy_exclamation_mark'=>'❗','heavy_heart_exclamation_mark_ornament'=>'❣','heart'=>'❤','heavy_plus_sign'=>'➕','heavy_minus_sign'=>'➖','heavy_division_sign'=>'➗','arrow_right'=>'➡','curly_loop'=>'➰','loop'=>'➿','arrow_heading_up'=>'⤴','arrow_heading_down'=>'⤵','arrow_left'=>'⬅','arrow_up'=>'⬆','arrow_down'=>'⬇','black_large_square'=>'⬛','white_large_square'=>'⬜','star'=>'⭐','o'=>'⭕','wavy_dash'=>'〰','part_alternation_mark'=>'〽','congratulations'=>'㊗','secret'=>'㊙','mahjong'=>'🀄','black_joker'=>'🃏','a'=>'🅰','b'=>'🅱','o2'=>'🅾','parking'=>'🅿','ab'=>'🆎','cl'=>'🆑','cool'=>'🆒','free'=>'🆓','id'=>'🆔','new'=>'🆕','ng'=>'🆖','ok'=>'🆗','sos'=>'🆘','up'=>'🆙','vs'=>'🆚','koko'=>'🈁','sa'=>'🈂','u7121'=>'🈚','u6307'=>'🈯','u7981'=>'🈲','u7a7a'=>'🈳','u5408'=>'🈴','u6e80'=>'🈵','u6709'=>'🈶','u6708'=>'🈷','u7533'=>'🈸','u5272'=>'🈹','u55b6'=>'🈺','ideograph_advantage'=>'🉐','accept'=>'🉑','cyclone'=>'🌀','foggy'=>'🌁','closed_umbrella'=>'🌂','night_with_stars'=>'🌃','sunrise_over_mountains'=>'🌄','sunrise'=>'🌅','city_sunset'=>'🌆','city_sunrise'=>'🌇','rainbow'=>'🌈','bridge_at_night'=>'🌉','ocean'=>'🌊','volcano'=>'🌋','milky_way'=>'🌌','earth_africa'=>'🌍','earth_americas'=>'🌎','earth_asia'=>'🌏','globe_with_meridians'=>'🌐','new_moon'=>'🌑','waxing_crescent_moon'=>'🌒','first_quarter_moon'=>'🌓','moon'=>'🌔','waxing_gibbous_moon'=>'🌔','full_moon'=>'🌕','waning_gibbous_moon'=>'🌖','last_quarter_moon'=>'🌗','waning_crescent_moon'=>'🌘','crescent_moon'=>'🌙','new_moon_with_face'=>'🌚','first_quarter_moon_with_face'=>'🌛','last_quarter_moon_with_face'=>'🌜','full_moon_with_face'=>'🌝','sun_with_face'=>'🌞','star2'=>'🌟','stars'=>'🌠','thermometer'=>'🌡','mostly_sunny'=>'🌤','sun_small_cloud'=>'🌤','barely_sunny'=>'🌥','sun_behind_cloud'=>'🌥','partly_sunny_rain'=>'🌦','sun_behind_rain_cloud'=>'🌦','rain_cloud'=>'🌧','snow_cloud'=>'🌨','lightning'=>'🌩','lightning_cloud'=>'🌩','tornado'=>'🌪','tornado_cloud'=>'🌪','fog'=>'🌫','wind_blowing_face'=>'🌬','hotdog'=>'🌭','taco'=>'🌮','burrito'=>'🌯','chestnut'=>'🌰','seedling'=>'🌱','evergreen_tree'=>'🌲','deciduous_tree'=>'🌳','palm_tree'=>'🌴','cactus'=>'🌵','hot_pepper'=>'🌶','tulip'=>'🌷','cherry_blossom'=>'🌸','rose'=>'🌹','hibiscus'=>'🌺','sunflower'=>'🌻','blossom'=>'🌼','corn'=>'🌽','ear_of_rice'=>'🌾','herb'=>'🌿','four_leaf_clover'=>'🍀','maple_leaf'=>'🍁','fallen_leaf'=>'🍂','leaves'=>'🍃','mushroom'=>'🍄','tomato'=>'🍅','eggplant'=>'🍆','grapes'=>'🍇','melon'=>'🍈','watermelon'=>'🍉','tangerine'=>'🍊','lemon'=>'🍋','banana'=>'🍌','pineapple'=>'🍍','apple'=>'🍎','green_apple'=>'🍏','pear'=>'🍐','peach'=>'🍑','cherries'=>'🍒','strawberry'=>'🍓','hamburger'=>'🍔','pizza'=>'🍕','meat_on_bone'=>'🍖','poultry_leg'=>'🍗','rice_cracker'=>'🍘','rice_ball'=>'🍙','rice'=>'🍚','curry'=>'🍛','ramen'=>'🍜','spaghetti'=>'🍝','bread'=>'🍞','fries'=>'🍟','sweet_potato'=>'🍠','dango'=>'🍡','oden'=>'🍢','sushi'=>'🍣','fried_shrimp'=>'🍤','fish_cake'=>'🍥','icecream'=>'🍦','shaved_ice'=>'🍧','ice_cream'=>'🍨','doughnut'=>'🍩','cookie'=>'🍪','chocolate_bar'=>'🍫','candy'=>'🍬','lollipop'=>'🍭','custard'=>'🍮','honey_pot'=>'🍯','cake'=>'🍰','bento'=>'🍱','stew'=>'🍲','egg'=>'🍳','fork_and_knife'=>'🍴','tea'=>'🍵','sake'=>'🍶','wine_glass'=>'🍷','cocktail'=>'🍸','tropical_drink'=>'🍹','beer'=>'🍺','beers'=>'🍻','baby_bottle'=>'🍼','knife_fork_plate'=>'🍽','champagne'=>'🍾','popcorn'=>'🍿','ribbon'=>'🎀','gift'=>'🎁','birthday'=>'🎂','jack_o_lantern'=>'🎃','christmas_tree'=>'🎄','santa'=>'🎅','fireworks'=>'🎆','sparkler'=>'🎇','balloon'=>'🎈','tada'=>'🎉','confetti_ball'=>'🎊','tanabata_tree'=>'🎋','crossed_flags'=>'🎌','bamboo'=>'🎍','dolls'=>'🎎','flags'=>'🎏','wind_chime'=>'🎐','rice_scene'=>'🎑','school_satchel'=>'🎒','mortar_board'=>'🎓','medal'=>'🎖','reminder_ribbon'=>'🎗','studio_microphone'=>'🎙','level_slider'=>'🎚','control_knobs'=>'🎛','film_frames'=>'🎞','admission_tickets'=>'🎟','carousel_horse'=>'🎠','ferris_wheel'=>'🎡','roller_coaster'=>'🎢','fishing_pole_and_fish'=>'🎣','microphone'=>'🎤','movie_camera'=>'🎥','cinema'=>'🎦','headphones'=>'🎧','art'=>'🎨','tophat'=>'🎩','circus_tent'=>'🎪','ticket'=>'🎫','clapper'=>'🎬','performing_arts'=>'🎭','video_game'=>'🎮','dart'=>'🎯','slot_machine'=>'🎰','8ball'=>'🎱','game_die'=>'🎲','bowling'=>'🎳','flower_playing_cards'=>'🎴','musical_note'=>'🎵','notes'=>'🎶','saxophone'=>'🎷','guitar'=>'🎸','musical_keyboard'=>'🎹','trumpet'=>'🎺','violin'=>'🎻','musical_score'=>'🎼','running_shirt_with_sash'=>'🎽','tennis'=>'🎾','ski'=>'🎿','basketball'=>'🏀','checkered_flag'=>'🏁','snowboarder'=>'🏂','runner'=>'🏃','running'=>'🏃','surfer'=>'🏄','sports_medal'=>'🏅','trophy'=>'🏆','horse_racing'=>'🏇','football'=>'🏈','rugby_football'=>'🏉','swimmer'=>'🏊','weight_lifter'=>'🏋','golfer'=>'🏌','racing_motorcycle'=>'🏍','racing_car'=>'🏎','cricket_bat_and_ball'=>'🏏','volleyball'=>'🏐','field_hockey_stick_and_ball'=>'🏑','ice_hockey_stick_and_puck'=>'🏒','table_tennis_paddle_and_ball'=>'🏓','snow_capped_mountain'=>'🏔','camping'=>'🏕','beach_with_umbrella'=>'🏖','building_construction'=>'🏗','house_buildings'=>'🏘','cityscape'=>'🏙','derelict_house_building'=>'🏚','classical_building'=>'🏛','desert'=>'🏜','desert_island'=>'🏝','national_park'=>'🏞','stadium'=>'🏟','house'=>'🏠','house_with_garden'=>'🏡','office'=>'🏢','post_office'=>'🏣','european_post_office'=>'🏤','hospital'=>'🏥','bank'=>'🏦','atm'=>'🏧','hotel'=>'🏨','love_hotel'=>'🏩','convenience_store'=>'🏪','school'=>'🏫','department_store'=>'🏬','factory'=>'🏭','izakaya_lantern'=>'🏮','lantern'=>'🏮','japanese_castle'=>'🏯','european_castle'=>'🏰','waving_white_flag'=>'🏳','waving_black_flag'=>'🏴','rosette'=>'🏵','label'=>'🏷','badminton_racquet_and_shuttlecock'=>'🏸','bow_and_arrow'=>'🏹','amphora'=>'🏺','skin-tone-2'=>'🏻','skin-tone-3'=>'🏼','skin-tone-4'=>'🏽','skin-tone-5'=>'🏾','skin-tone-6'=>'🏿','rat'=>'🐀','mouse2'=>'🐁','ox'=>'🐂','water_buffalo'=>'🐃','cow2'=>'🐄','tiger2'=>'🐅','leopard'=>'🐆','rabbit2'=>'🐇','cat2'=>'🐈','dragon'=>'🐉','crocodile'=>'🐊','whale2'=>'🐋','snail'=>'🐌','snake'=>'🐍','racehorse'=>'🐎','ram'=>'🐏','goat'=>'🐐','sheep'=>'🐑','monkey'=>'🐒','rooster'=>'🐓','chicken'=>'🐔','dog2'=>'🐕','pig2'=>'🐖','boar'=>'🐗','elephant'=>'🐘','octopus'=>'🐙','shell'=>'🐚','bug'=>'🐛','ant'=>'🐜','bee'=>'🐝','honeybee'=>'🐝','beetle'=>'🐞','fish'=>'🐟','tropical_fish'=>'🐠','blowfish'=>'🐡','turtle'=>'🐢','hatching_chick'=>'🐣','baby_chick'=>'🐤','hatched_chick'=>'🐥','bird'=>'🐦','penguin'=>'🐧','koala'=>'🐨','poodle'=>'🐩','dromedary_camel'=>'🐪','camel'=>'🐫','dolphin'=>'🐬','flipper'=>'🐬','mouse'=>'🐭','cow'=>'🐮','tiger'=>'🐯','rabbit'=>'🐰','cat'=>'🐱','dragon_face'=>'🐲','whale'=>'🐳','horse'=>'🐴','monkey_face'=>'🐵','dog'=>'🐶','pig'=>'🐷','frog'=>'🐸','hamster'=>'🐹','wolf'=>'🐺','bear'=>'🐻','panda_face'=>'🐼','pig_nose'=>'🐽','feet'=>'🐾','paw_prints'=>'🐾','chipmunk'=>'🐿','eyes'=>'👀','eye'=>'👁','ear'=>'👂','nose'=>'👃','lips'=>'👄','tongue'=>'👅','point_up_2'=>'👆','point_down'=>'👇','point_left'=>'👈','point_right'=>'👉','facepunch'=>'👊','punch'=>'👊','wave'=>'👋','ok_hand'=>'👌','+1'=>'👍','thumbsup'=>'👍','-1'=>'👎','thumbsdown'=>'👎','clap'=>'👏','open_hands'=>'👐','crown'=>'👑','womans_hat'=>'👒','eyeglasses'=>'👓','necktie'=>'👔','shirt'=>'👕','tshirt'=>'👕','jeans'=>'👖','dress'=>'👗','kimono'=>'👘','bikini'=>'👙','womans_clothes'=>'👚','purse'=>'👛','handbag'=>'👜','pouch'=>'👝','mans_shoe'=>'👞','shoe'=>'👞','athletic_shoe'=>'👟','high_heel'=>'👠','sandal'=>'👡','boot'=>'👢','footprints'=>'👣','bust_in_silhouette'=>'👤','busts_in_silhouette'=>'👥','boy'=>'👦','girl'=>'👧','man'=>'👨','woman'=>'👩','family'=>'👪','man-woman-boy'=>'👪','couple'=>'👫','man_and_woman_holding_hands'=>'👫','two_men_holding_hands'=>'👬','two_women_holding_hands'=>'👭','cop'=>'👮','dancers'=>'👯','bride_with_veil'=>'👰','person_with_blond_hair'=>'👱','man_with_gua_pi_mao'=>'👲','man_with_turban'=>'👳','older_man'=>'👴','older_woman'=>'👵','baby'=>'👶','construction_worker'=>'👷','princess'=>'👸','japanese_ogre'=>'👹','japanese_goblin'=>'👺','ghost'=>'👻','angel'=>'👼','alien'=>'👽','space_invader'=>'👾','imp'=>'👿','skull'=>'💀','information_desk_person'=>'💁','guardsman'=>'💂','dancer'=>'💃','lipstick'=>'💄','nail_care'=>'💅','massage'=>'💆','haircut'=>'💇','barber'=>'💈','syringe'=>'💉','pill'=>'💊','kiss'=>'💋','love_letter'=>'💌','ring'=>'💍','gem'=>'💎','couplekiss'=>'💏','bouquet'=>'💐','couple_with_heart'=>'💑','wedding'=>'💒','heartbeat'=>'💓','broken_heart'=>'💔','two_hearts'=>'💕','sparkling_heart'=>'💖','heartpulse'=>'💗','cupid'=>'💘','blue_heart'=>'💙','green_heart'=>'💚','yellow_heart'=>'💛','purple_heart'=>'💜','gift_heart'=>'💝','revolving_hearts'=>'💞','heart_decoration'=>'💟','diamond_shape_with_a_dot_inside'=>'💠','bulb'=>'💡','anger'=>'💢','bomb'=>'💣','zzz'=>'💤','boom'=>'💥','collision'=>'💥','sweat_drops'=>'💦','droplet'=>'💧','dash'=>'💨','hankey'=>'💩','poop'=>'💩','shit'=>'💩','muscle'=>'💪','dizzy'=>'💫','speech_balloon'=>'💬','thought_balloon'=>'💭','white_flower'=>'💮','100'=>'💯','moneybag'=>'💰','currency_exchange'=>'💱','heavy_dollar_sign'=>'💲','credit_card'=>'💳','yen'=>'💴','dollar'=>'💵','euro'=>'💶','pound'=>'💷','money_with_wings'=>'💸','chart'=>'💹','seat'=>'💺','computer'=>'💻','briefcase'=>'💼','minidisc'=>'💽','floppy_disk'=>'💾','cd'=>'💿','dvd'=>'📀','file_folder'=>'📁','open_file_folder'=>'📂','page_with_curl'=>'📃','page_facing_up'=>'📄','date'=>'📅','calendar'=>'📆','card_index'=>'📇','chart_with_upwards_trend'=>'📈','chart_with_downwards_trend'=>'📉','bar_chart'=>'📊','clipboard'=>'📋','pushpin'=>'📌','round_pushpin'=>'📍','paperclip'=>'📎','straight_ruler'=>'📏','triangular_ruler'=>'📐','bookmark_tabs'=>'📑','ledger'=>'📒','notebook'=>'📓','notebook_with_decorative_cover'=>'📔','closed_book'=>'📕','book'=>'📖','open_book'=>'📖','green_book'=>'📗','blue_book'=>'📘','orange_book'=>'📙','books'=>'📚','name_badge'=>'📛','scroll'=>'📜','memo'=>'📝','pencil'=>'📝','telephone_receiver'=>'📞','pager'=>'📟','fax'=>'📠','satellite_antenna'=>'📡','loudspeaker'=>'📢','mega'=>'📣','outbox_tray'=>'📤','inbox_tray'=>'📥','package'=>'📦','e-mail'=>'📧','incoming_envelope'=>'📨','envelope_with_arrow'=>'📩','mailbox_closed'=>'📪','mailbox'=>'📫','mailbox_with_mail'=>'📬','mailbox_with_no_mail'=>'📭','postbox'=>'📮','postal_horn'=>'📯','newspaper'=>'📰','iphone'=>'📱','calling'=>'📲','vibration_mode'=>'📳','mobile_phone_off'=>'📴','no_mobile_phones'=>'📵','signal_strength'=>'📶','camera'=>'📷','camera_with_flash'=>'📸','video_camera'=>'📹','tv'=>'📺','radio'=>'📻','vhs'=>'📼','film_projector'=>'📽','prayer_beads'=>'📿','twisted_rightwards_arrows'=>'🔀','repeat'=>'🔁','repeat_one'=>'🔂','arrows_clockwise'=>'🔃','arrows_counterclockwise'=>'🔄','low_brightness'=>'🔅','high_brightness'=>'🔆','mute'=>'🔇','speaker'=>'🔈','sound'=>'🔉','loud_sound'=>'🔊','battery'=>'🔋','electric_plug'=>'🔌','mag'=>'🔍','mag_right'=>'🔎','lock_with_ink_pen'=>'🔏','closed_lock_with_key'=>'🔐','key'=>'🔑','lock'=>'🔒','unlock'=>'🔓','bell'=>'🔔','no_bell'=>'🔕','bookmark'=>'🔖','link'=>'🔗','radio_button'=>'🔘','back'=>'🔙','end'=>'🔚','on'=>'🔛','soon'=>'🔜','top'=>'🔝','underage'=>'🔞','keycap_ten'=>'🔟','capital_abcd'=>'🔠','abcd'=>'🔡','1234'=>'🔢','symbols'=>'🔣','abc'=>'🔤','fire'=>'🔥','flashlight'=>'🔦','wrench'=>'🔧','hammer'=>'🔨','nut_and_bolt'=>'🔩','hocho'=>'🔪','knife'=>'🔪','gun'=>'🔫','microscope'=>'🔬','telescope'=>'🔭','crystal_ball'=>'🔮','six_pointed_star'=>'🔯','beginner'=>'🔰','trident'=>'🔱','black_square_button'=>'🔲','white_square_button'=>'🔳','red_circle'=>'🔴','large_blue_circle'=>'🔵','large_orange_diamond'=>'🔶','large_blue_diamond'=>'🔷','small_orange_diamond'=>'🔸','small_blue_diamond'=>'🔹','small_red_triangle'=>'🔺','small_red_triangle_down'=>'🔻','arrow_up_small'=>'🔼','arrow_down_small'=>'🔽','om_symbol'=>'🕉','dove_of_peace'=>'🕊','kaaba'=>'🕋','mosque'=>'🕌','synagogue'=>'🕍','menorah_with_nine_branches'=>'🕎','clock1'=>'🕐','clock2'=>'🕑','clock3'=>'🕒','clock4'=>'🕓','clock5'=>'🕔','clock6'=>'🕕','clock7'=>'🕖','clock8'=>'🕗','clock9'=>'🕘','clock10'=>'🕙','clock11'=>'🕚','clock12'=>'🕛','clock130'=>'🕜','clock230'=>'🕝','clock330'=>'🕞','clock430'=>'🕟','clock530'=>'🕠','clock630'=>'🕡','clock730'=>'🕢','clock830'=>'🕣','clock930'=>'🕤','clock1030'=>'🕥','clock1130'=>'🕦','clock1230'=>'🕧','candle'=>'🕯','mantelpiece_clock'=>'🕰','hole'=>'🕳','man_in_business_suit_levitating'=>'🕴','sleuth_or_spy'=>'🕵','dark_sunglasses'=>'🕶','spider'=>'🕷','spider_web'=>'🕸','joystick'=>'🕹','linked_paperclips'=>'🖇','lower_left_ballpoint_pen'=>'🖊','lower_left_fountain_pen'=>'🖋','lower_left_paintbrush'=>'🖌','lower_left_crayon'=>'🖍','raised_hand_with_fingers_splayed'=>'🖐','middle_finger'=>'🖕','reversed_hand_with_middle_finger_extended'=>'🖕','spock-hand'=>'🖖','desktop_computer'=>'🖥','printer'=>'🖨','three_button_mouse'=>'🖱','trackball'=>'🖲','frame_with_picture'=>'🖼','card_index_dividers'=>'🗂','card_file_box'=>'🗃','file_cabinet'=>'🗄','wastebasket'=>'🗑','spiral_note_pad'=>'🗒','spiral_calendar_pad'=>'🗓','compression'=>'🗜','old_key'=>'🗝','rolled_up_newspaper'=>'🗞','dagger_knife'=>'🗡','speaking_head_in_silhouette'=>'🗣','left_speech_bubble'=>'🗨','right_anger_bubble'=>'🗯','ballot_box_with_ballot'=>'🗳','world_map'=>'🗺','mount_fuji'=>'🗻','tokyo_tower'=>'🗼','statue_of_liberty'=>'🗽','japan'=>'🗾','moyai'=>'🗿','grinning'=>'😀','grin'=>'😁','joy'=>'😂','smiley'=>'😃','smile'=>'😄','simple_smile'=>'🙂','sweat_smile'=>'😅','laughing'=>'😆','satisfied'=>'😆','innocent'=>'😇','smiling_imp'=>'😈','wink'=>'😉','blush'=>'😊','yum'=>'😋','relieved'=>'😌','heart_eyes'=>'😍','sunglasses'=>'😎','smirk'=>'😏','neutral_face'=>'😐','expressionless'=>'😑','unamused'=>'😒','sweat'=>'😓','pensive'=>'😔','confused'=>'😕','confounded'=>'😖','kissing'=>'😗','kissing_heart'=>'😘','kissing_smiling_eyes'=>'😙','kissing_closed_eyes'=>'😚','stuck_out_tongue'=>'😛','stuck_out_tongue_winking_eye'=>'😜','stuck_out_tongue_closed_eyes'=>'😝','disappointed'=>'😞','worried'=>'😟','angry'=>'😠','rage'=>'😡','cry'=>'😢','persevere'=>'😣','triumph'=>'😤','disappointed_relieved'=>'😥','frowning'=>'😦','anguished'=>'😧','fearful'=>'😨','weary'=>'😩','sleepy'=>'😪','tired_face'=>'😫','grimacing'=>'😬','sob'=>'😭','open_mouth'=>'😮','hushed'=>'😯','cold_sweat'=>'😰','scream'=>'😱','astonished'=>'😲','flushed'=>'😳','sleeping'=>'😴','dizzy_face'=>'😵','no_mouth'=>'😶','mask'=>'😷','smile_cat'=>'😸','joy_cat'=>'😹','smiley_cat'=>'😺','heart_eyes_cat'=>'😻','smirk_cat'=>'😼','kissing_cat'=>'😽','pouting_cat'=>'😾','crying_cat_face'=>'😿','scream_cat'=>'🙀','slightly_frowning_face'=>'🙁','slightly_smiling_face'=>'🙂','upside_down_face'=>'🙃','face_with_rolling_eyes'=>'🙄','no_good'=>'🙅','ok_woman'=>'🙆','bow'=>'🙇','see_no_evil'=>'🙈','hear_no_evil'=>'🙉','speak_no_evil'=>'🙊','raising_hand'=>'🙋','raised_hands'=>'🙌','person_frowning'=>'🙍','person_with_pouting_face'=>'🙎','pray'=>'🙏','rocket'=>'🚀','helicopter'=>'🚁','steam_locomotive'=>'🚂','railway_car'=>'🚃','bullettrain_side'=>'🚄','bullettrain_front'=>'🚅','train2'=>'🚆','metro'=>'🚇','light_rail'=>'🚈','station'=>'🚉','tram'=>'🚊','train'=>'🚋','bus'=>'🚌','oncoming_bus'=>'🚍','trolleybus'=>'🚎','busstop'=>'🚏','minibus'=>'🚐','ambulance'=>'🚑','fire_engine'=>'🚒','police_car'=>'🚓','oncoming_police_car'=>'🚔','taxi'=>'🚕','oncoming_taxi'=>'🚖','car'=>'🚗','red_car'=>'🚗','oncoming_automobile'=>'🚘','blue_car'=>'🚙','truck'=>'🚚','articulated_lorry'=>'🚛','tractor'=>'🚜','monorail'=>'🚝','mountain_railway'=>'🚞','suspension_railway'=>'🚟','mountain_cableway'=>'🚠','aerial_tramway'=>'🚡','ship'=>'🚢','rowboat'=>'🚣','speedboat'=>'🚤','traffic_light'=>'🚥','vertical_traffic_light'=>'🚦','construction'=>'🚧','rotating_light'=>'🚨','triangular_flag_on_post'=>'🚩','door'=>'🚪','no_entry_sign'=>'🚫','smoking'=>'🚬','no_smoking'=>'🚭','put_litter_in_its_place'=>'🚮','do_not_litter'=>'🚯','potable_water'=>'🚰','non-potable_water'=>'🚱','bike'=>'🚲','no_bicycles'=>'🚳','bicyclist'=>'🚴','mountain_bicyclist'=>'🚵','walking'=>'🚶','no_pedestrians'=>'🚷','children_crossing'=>'🚸','mens'=>'🚹','womens'=>'🚺','restroom'=>'🚻','baby_symbol'=>'🚼','toilet'=>'🚽','wc'=>'🚾','shower'=>'🚿','bath'=>'🛀','bathtub'=>'🛁','passport_control'=>'🛂','customs'=>'🛃','baggage_claim'=>'🛄','left_luggage'=>'🛅','couch_and_lamp'=>'🛋','sleeping_accommodation'=>'🛌','shopping_bags'=>'🛍','bellhop_bell'=>'🛎','bed'=>'🛏','place_of_worship'=>'🛐','hammer_and_wrench'=>'🛠','shield'=>'🛡','oil_drum'=>'🛢','motorway'=>'🛣','railway_track'=>'🛤','motor_boat'=>'🛥','small_airplane'=>'🛩','airplane_departure'=>'🛫','airplane_arriving'=>'🛬','satellite'=>'🛰','passenger_ship'=>'🛳','zipper_mouth_face'=>'🤐','money_mouth_face'=>'🤑','face_with_thermometer'=>'🤒','nerd_face'=>'🤓','thinking_face'=>'🤔','face_with_head_bandage'=>'🤕','robot_face'=>'🤖','hugging_face'=>'🤗','the_horns'=>'🤘','sign_of_the_horns'=>'🤘','crab'=>'🦀','lion_face'=>'🦁','scorpion'=>'🦂','turkey'=>'🦃','unicorn_face'=>'🦄','cheese_wedge'=>'🧀','hash'=>'#⃣','keycap_star'=>'*⃣','zero'=>'0⃣','one'=>'1⃣','two'=>'2⃣','three'=>'3⃣','four'=>'4⃣','five'=>'5⃣','six'=>'6⃣','seven'=>'7⃣','eight'=>'8⃣','nine'=>'9⃣','flag-ac'=>'🇦🇨','flag-ad'=>'🇦🇩','flag-ae'=>'🇦🇪','flag-af'=>'🇦🇫','flag-ag'=>'🇦🇬','flag-ai'=>'🇦🇮','flag-al'=>'🇦🇱','flag-am'=>'🇦🇲','flag-ao'=>'🇦🇴','flag-aq'=>'🇦🇶','flag-ar'=>'🇦🇷','flag-as'=>'🇦🇸','flag-at'=>'🇦🇹','flag-au'=>'🇦🇺','flag-aw'=>'🇦🇼','flag-ax'=>'🇦🇽','flag-az'=>'🇦🇿','flag-ba'=>'🇧🇦','flag-bb'=>'🇧🇧','flag-bd'=>'🇧🇩','flag-be'=>'🇧🇪','flag-bf'=>'🇧🇫','flag-bg'=>'🇧🇬','flag-bh'=>'🇧🇭','flag-bi'=>'🇧🇮','flag-bj'=>'🇧🇯','flag-bl'=>'🇧🇱','flag-bm'=>'🇧🇲','flag-bn'=>'🇧🇳','flag-bo'=>'🇧🇴','flag-bq'=>'🇧🇶','flag-br'=>'🇧🇷','flag-bs'=>'🇧🇸','flag-bt'=>'🇧🇹','flag-bv'=>'🇧🇻','flag-bw'=>'🇧🇼','flag-by'=>'🇧🇾','flag-bz'=>'🇧🇿','flag-ca'=>'🇨🇦','flag-cc'=>'🇨🇨','flag-cd'=>'🇨🇩','flag-cf'=>'🇨🇫','flag-cg'=>'🇨🇬','flag-ch'=>'🇨🇭','flag-ci'=>'🇨🇮','flag-ck'=>'🇨🇰','flag-cl'=>'🇨🇱','flag-cm'=>'🇨🇲','flag-cn'=>'🇨🇳','cn'=>'🇨🇳','flag-co'=>'🇨🇴','flag-cp'=>'🇨🇵','flag-cr'=>'🇨🇷','flag-cu'=>'🇨🇺','flag-cv'=>'🇨🇻','flag-cw'=>'🇨🇼','flag-cx'=>'🇨🇽','flag-cy'=>'🇨🇾','flag-cz'=>'🇨🇿','flag-de'=>'🇩🇪','de'=>'🇩🇪','flag-dg'=>'🇩🇬','flag-dj'=>'🇩🇯','flag-dk'=>'🇩🇰','flag-dm'=>'🇩🇲','flag-do'=>'🇩🇴','flag-dz'=>'🇩🇿','flag-ea'=>'🇪🇦','flag-ec'=>'🇪🇨','flag-ee'=>'🇪🇪','flag-eg'=>'🇪🇬','flag-eh'=>'🇪🇭','flag-er'=>'🇪🇷','flag-es'=>'🇪🇸','es'=>'🇪🇸','flag-et'=>'🇪🇹','flag-eu'=>'🇪🇺','flag-fi'=>'🇫🇮','flag-fj'=>'🇫🇯','flag-fk'=>'🇫🇰','flag-fm'=>'🇫🇲','flag-fo'=>'🇫🇴','flag-fr'=>'🇫🇷','fr'=>'🇫🇷','flag-ga'=>'🇬🇦','flag-gb'=>'🇬🇧','gb'=>'🇬🇧','uk'=>'🇬🇧','flag-gd'=>'🇬🇩','flag-ge'=>'🇬🇪','flag-gf'=>'🇬🇫','flag-gg'=>'🇬🇬','flag-gh'=>'🇬🇭','flag-gi'=>'🇬🇮','flag-gl'=>'🇬🇱','flag-gm'=>'🇬🇲','flag-gn'=>'🇬🇳','flag-gp'=>'🇬🇵','flag-gq'=>'🇬🇶','flag-gr'=>'🇬🇷','flag-gs'=>'🇬🇸','flag-gt'=>'🇬🇹','flag-gu'=>'🇬🇺','flag-gw'=>'🇬🇼','flag-gy'=>'🇬🇾','flag-hk'=>'🇭🇰','flag-hm'=>'🇭🇲','flag-hn'=>'🇭🇳','flag-hr'=>'🇭🇷','flag-ht'=>'🇭🇹','flag-hu'=>'🇭🇺','flag-ic'=>'🇮🇨','flag-id'=>'🇮🇩','flag-ie'=>'🇮🇪','flag-il'=>'🇮🇱','flag-im'=>'🇮🇲','flag-in'=>'🇮🇳','flag-io'=>'🇮🇴','flag-iq'=>'🇮🇶','flag-ir'=>'🇮🇷','flag-is'=>'🇮🇸','flag-it'=>'🇮🇹','it'=>'🇮🇹','flag-je'=>'🇯🇪','flag-jm'=>'🇯🇲','flag-jo'=>'🇯🇴','flag-jp'=>'🇯🇵','jp'=>'🇯🇵','flag-ke'=>'🇰🇪','flag-kg'=>'🇰🇬','flag-kh'=>'🇰🇭','flag-ki'=>'🇰🇮','flag-km'=>'🇰🇲','flag-kn'=>'🇰🇳','flag-kp'=>'🇰🇵','flag-kr'=>'🇰🇷','kr'=>'🇰🇷','flag-kw'=>'🇰🇼','flag-ky'=>'🇰🇾','flag-kz'=>'🇰🇿','flag-la'=>'🇱🇦','flag-lb'=>'🇱🇧','flag-lc'=>'🇱🇨','flag-li'=>'🇱🇮','flag-lk'=>'🇱🇰','flag-lr'=>'🇱🇷','flag-ls'=>'🇱🇸','flag-lt'=>'🇱🇹','flag-lu'=>'🇱🇺','flag-lv'=>'🇱🇻','flag-ly'=>'🇱🇾','flag-ma'=>'🇲🇦','flag-mc'=>'🇲🇨','flag-md'=>'🇲🇩','flag-me'=>'🇲🇪','flag-mf'=>'🇲🇫','flag-mg'=>'🇲🇬','flag-mh'=>'🇲🇭','flag-mk'=>'🇲🇰','flag-ml'=>'🇲🇱','flag-mm'=>'🇲🇲','flag-mn'=>'🇲🇳','flag-mo'=>'🇲🇴','flag-mp'=>'🇲🇵','flag-mq'=>'🇲🇶','flag-mr'=>'🇲🇷','flag-ms'=>'🇲🇸','flag-mt'=>'🇲🇹','flag-mu'=>'🇲🇺','flag-mv'=>'🇲🇻','flag-mw'=>'🇲🇼','flag-mx'=>'🇲🇽','flag-my'=>'🇲🇾','flag-mz'=>'🇲🇿','flag-na'=>'🇳🇦','flag-nc'=>'🇳🇨','flag-ne'=>'🇳🇪','flag-nf'=>'🇳🇫','flag-ng'=>'🇳🇬','flag-ni'=>'🇳🇮','flag-nl'=>'🇳🇱','flag-no'=>'🇳🇴','flag-np'=>'🇳🇵','flag-nr'=>'🇳🇷','flag-nu'=>'🇳🇺','flag-nz'=>'🇳🇿','flag-om'=>'🇴🇲','flag-pa'=>'🇵🇦','flag-pe'=>'🇵🇪','flag-pf'=>'🇵🇫','flag-pg'=>'🇵🇬','flag-ph'=>'🇵🇭','flag-pk'=>'🇵🇰','flag-pl'=>'🇵🇱','flag-pm'=>'🇵🇲','flag-pn'=>'🇵🇳','flag-pr'=>'🇵🇷','flag-ps'=>'🇵🇸','flag-pt'=>'🇵🇹','flag-pw'=>'🇵🇼','flag-py'=>'🇵🇾','flag-qa'=>'🇶🇦','flag-re'=>'🇷🇪','flag-ro'=>'🇷🇴','flag-rs'=>'🇷🇸','flag-ru'=>'🇷🇺','ru'=>'🇷🇺','flag-rw'=>'🇷🇼','flag-sa'=>'🇸🇦','flag-sb'=>'🇸🇧','flag-sc'=>'🇸🇨','flag-sd'=>'🇸🇩','flag-se'=>'🇸🇪','flag-sg'=>'🇸🇬','flag-sh'=>'🇸🇭','flag-si'=>'🇸🇮','flag-sj'=>'🇸🇯','flag-sk'=>'🇸🇰','flag-sl'=>'🇸🇱','flag-sm'=>'🇸🇲','flag-sn'=>'🇸🇳','flag-so'=>'🇸🇴','flag-sr'=>'🇸🇷','flag-ss'=>'🇸🇸','flag-st'=>'🇸🇹','flag-sv'=>'🇸🇻','flag-sx'=>'🇸🇽','flag-sy'=>'🇸🇾','flag-sz'=>'🇸🇿','flag-ta'=>'🇹🇦','flag-tc'=>'🇹🇨','flag-td'=>'🇹🇩','flag-tf'=>'🇹🇫','flag-tg'=>'🇹🇬','flag-th'=>'🇹🇭','flag-tj'=>'🇹🇯','flag-tk'=>'🇹🇰','flag-tl'=>'🇹🇱','flag-tm'=>'🇹🇲','flag-tn'=>'🇹🇳','flag-to'=>'🇹🇴','flag-tr'=>'🇹🇷','flag-tt'=>'🇹🇹','flag-tv'=>'🇹🇻','flag-tw'=>'🇹🇼','flag-tz'=>'🇹🇿','flag-ua'=>'🇺🇦','flag-ug'=>'🇺🇬','flag-um'=>'🇺🇲','flag-us'=>'🇺🇸','us'=>'🇺🇸','flag-uy'=>'🇺🇾','flag-uz'=>'🇺🇿','flag-va'=>'🇻🇦','flag-vc'=>'🇻🇨','flag-ve'=>'🇻🇪','flag-vg'=>'🇻🇬','flag-vi'=>'🇻🇮','flag-vn'=>'🇻🇳','flag-vu'=>'🇻🇺','flag-wf'=>'🇼🇫','flag-ws'=>'🇼🇸','flag-xk'=>'🇽🇰','flag-ye'=>'🇾🇪','flag-yt'=>'🇾🇹','flag-za'=>'🇿🇦','flag-zm'=>'🇿🇲','flag-zw'=>'🇿🇼','man-man-boy'=>'👨‍👨‍👦','man-man-boy-boy'=>'👨‍👨‍👦‍👦','man-man-girl'=>'👨‍👨‍👧','man-man-girl-boy'=>'👨‍👨‍👧‍👦','man-man-girl-girl'=>'👨‍👨‍👧‍👧','man-woman-boy-boy'=>'👨‍👩‍👦‍👦','man-woman-girl'=>'👨‍👩‍👧','man-woman-girl-boy'=>'👨‍👩‍👧‍👦','man-woman-girl-girl'=>'👨‍👩‍👧‍👧','man-heart-man'=>'👨‍❤️‍👨','man-kiss-man'=>'👨‍❤️‍💋‍👨','woman-woman-boy'=>'👩‍👩‍👦','woman-woman-boy-boy'=>'👩‍👩‍👦‍👦','woman-woman-girl'=>'👩‍👩‍👧','woman-woman-girl-boy'=>'👩‍👩‍👧‍👦','woman-woman-girl-girl'=>'👩‍👩‍👧‍👧','woman-heart-woman'=>'👩‍❤️‍👩','woman-kiss-woman'=>'👩‍❤️‍💋‍👩'); | |
preg_match_all("/:([a-zA-Z0-9'_+-]+):/", $message, $emojis); | |
foreach ($emojis[1] as $emojiname) { | |
$message = str_replace(":". $emojiname.":", $emoji_unicode[$emojiname], $message); | |
} | |
$htmlMessage = "<div id='$message_timestamp'><img src='$gravatar' /><div class='message'><div class='username'>$username</div><div class='time'><a href='#$message_timestamp'>$message_date</a></div><div class='msg'>$message</div></div></div>"; | |
$xml_export_array[ $channel ][ $date ][] = [ $htmlMessage ]; | |
} | |
} | |
} | |
} | |
} | |
krsort( $xml_export_array ); | |
$xml_file_markup = new DOMDocument( "1.0", "UTF-8" ); | |
$xml_file_markup->formatOutput = true; | |
$rss_element = $xml_file_markup->createElement( 'rss' ); | |
$xml_file_markup->appendChild( $rss_element ); | |
$xml_file_markup->createAttributeNS( 'http://wordpress.org/export/1.2/excerpt/', 'excerpt:attr' ); | |
$xml_file_markup->createAttributeNS( 'http://purl.org/rss/1.0/modules/content/', 'content:attr' ); | |
$xml_file_markup->createAttributeNS( 'http://wellformedweb.org/CommentAPI/', 'wfw:attr' ); | |
$xml_file_markup->createAttributeNS( 'http://purl.org/dc/elements/1.1/', 'dc:attr' ); | |
$xml_file_markup->createAttributeNS( 'http://wordpress.org/export/1.2/', 'wp:attr' ); | |
$channel_element = $xml_file_markup->createElement( 'channel' ); | |
$rss_element->appendChild( $channel_element ); | |
$title_element = $xml_file_markup->createElement( 'title', 'Slack-Archiv' ); | |
$channel_element->appendChild( $title_element ); | |
$description_element = $xml_file_markup->createElement( 'description', 'Slack-Archiv des DEWP-Teams' ); | |
$channel_element->appendChild( $description_element ); | |
$pubDate_element = $xml_file_markup->createElement( 'pubDate', 'Thu, 28 Jul 2016 07:23:02 +0000' ); | |
$channel_element->appendChild( $pubDate_element ); | |
$language_element = $xml_file_markup->createElement( 'language', 'de-DE' ); | |
$channel_element->appendChild( $language_element ); | |
$wxr_version_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:wxr_version', '1.2' ); | |
$channel_element->appendChild( $wxr_version_element ); | |
$base_site_url_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:base_site_url', 'https://example.com/' ); | |
$channel_element->appendChild( $base_site_url_element ); | |
$base_blog_url_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:base_blog_url', 'https://example.com/' ); | |
$channel_element->appendChild( $base_blog_url_element ); | |
$author_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:author' ); | |
$channel_element->appendChild( $author_element ); | |
$author_id_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:author_id', 1 ); | |
$author_element->appendChild( $author_id_element ); | |
$author_login_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:author_login' ); | |
$author_element->appendChild( $author_login_element ); | |
$author_login_element->appendChild( $xml_file_markup->createCDATASection( 'author' ) ); | |
$author_email_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:author_email' ); | |
$author_element->appendChild( $author_email_element ); | |
$author_email_element->appendChild( $xml_file_markup->createCDATASection( 'author@example.com' ) ); | |
$author_display_name_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:author_display_name' ); | |
$author_element->appendChild( $author_display_name_element ); | |
$author_display_name_element->appendChild( $xml_file_markup->createCDATASection( 'Author' ) ); | |
$author_first_name_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:author_first_name' ); | |
$author_element->appendChild( $author_first_name_element ); | |
$author_last_name_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:author_last_name' ); | |
$author_element->appendChild( $author_last_name_element ); | |
foreach ( $xml_export_array as $key => $value ) { | |
$channel = $key; | |
foreach ( $value as $date => $message_array ) { | |
$timestamp = strtotime( $date ); | |
$date = date( 'd.m.Y', $timestamp ); | |
$title = "#$channel am $date"; | |
$pub_date = date( 'D, d M Y 10:00:00 +0000', $timestamp ); | |
$post_date = date( 'Y-m-d 10:00:00', $timestamp ); | |
$post_date_gmt = gmdate( 'Y-m-d H:i:s', strtotime( $post_date ) ); | |
$category_nicename = str_replace( '_', '-', $channel ); | |
$post_markup = '<div class="messages" style="clear:both;">'; | |
foreach ( $message_array as $message ) { | |
$post_markup .= $message[0]; | |
} | |
$post_markup .= '</div>'; | |
$item_element = $xml_file_markup->createElement( 'item' ); | |
$channel_element->appendChild( $item_element ); | |
$title_element = $xml_file_markup->createElement( 'title', $title ); | |
$item_element->appendChild( $title_element ); | |
$pubDate_element = $xml_file_markup->createElement( 'pubDate', $pub_date ); | |
$item_element->appendChild( $pubDate_element ); | |
$creator_element = $xml_file_markup->createElementNS( 'http://purl.org/dc/elements/1.1/', 'dc:creator' ); | |
$item_element->appendChild( $creator_element ); | |
$creator_element->appendChild( $xml_file_markup->createCDATASection( 'florian' ) ); | |
$content_element = $xml_file_markup->createElementNS( 'http://purl.org/rss/1.0/modules/content/', 'content:encoded' ); | |
$item_element->appendChild( $content_element ); | |
$content_element->appendChild( $xml_file_markup->createCDATASection( $post_markup ) ); | |
$excerpt_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/excerpt/', 'excerpt:encoded' ); | |
$item_element->appendChild( $excerpt_element ); | |
$excerpt_element->appendChild( $xml_file_markup->createCDATASection( '' ) ); | |
$post_date_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:post_date' ); | |
$item_element->appendChild( $post_date_element ); | |
$post_date_element->appendChild( $xml_file_markup->createCDATASection( $post_date ) ); | |
$post_date_gmt_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:post_date_gmt' ); | |
$item_element->appendChild( $post_date_gmt_element ); | |
$post_date_gmt_element->appendChild( $xml_file_markup->createCDATASection( $post_date_gmt ) ); | |
$comment_status_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:comment_status' ); | |
$item_element->appendChild( $comment_status_element ); | |
$comment_status_element->appendChild( $xml_file_markup->createCDATASection( 'closed' ) ); | |
$ping_status_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:ping_status' ); | |
$item_element->appendChild( $ping_status_element ); | |
$ping_status_element->appendChild( $xml_file_markup->createCDATASection( 'closed' ) ); | |
$status_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:status' ); | |
$item_element->appendChild( $status_element ); | |
$status_element->appendChild( $xml_file_markup->createCDATASection( 'publish' ) ); | |
$post_parent_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:post_parent', '0' ); | |
$item_element->appendChild( $post_parent_element ); | |
$menu_order_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:menu_order', '0' ); | |
$item_element->appendChild( $menu_order_element ); | |
$post_type_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:post_type' ); | |
$item_element->appendChild( $post_type_element ); | |
$post_type_element->appendChild( $xml_file_markup->createCDATASection( 'post' ) ); | |
$post_password_element = $xml_file_markup->createElementNS( 'http://wordpress.org/export/1.2/', 'wp:post_password' ); | |
$item_element->appendChild( $post_password_element ); | |
$post_password_element->appendChild( $xml_file_markup->createCDATASection( '' ) ); | |
$category_element = $xml_file_markup->createElement( 'category' ); | |
$item_element->appendChild( $category_element ); | |
$category_element->setAttribute( 'domain', 'category' ); | |
$category_element->setAttribute( 'nicename', $category_nicename ); | |
$category_element->appendChild( $xml_file_markup->createCDATASection( "#$channel" ) ); | |
} | |
} | |
if ( $start_date != "" && $end_date != "" ) { | |
$xml_file_markup->save( "slack-export-wxr-$start_date-$end_date.xml" ); | |
} elseif ($start_date != "") { | |
$xml_file_markup->save( "slack-export-wxr-start_date-$start_date.xml" ); | |
} elseif($end_date != "") { | |
$xml_file_markup->save( "slack-export-wxr-end_date-$end_date.xml" ); | |
} else { | |
$xml_file_markup->save( "slack-export-wxr.xml" ); | |
} | |
# Parsedown | |
# http://parsedown.org | |
# | |
# (c) Emanuil Rusev | |
# http://erusev.com | |
# | |
# For the full license information, view the LICENSE file that was distributed | |
# with this source code. | |
# | |
# | |
class Parsedown | |
{ | |
# ~ | |
const version = '1.6.0'; | |
# ~ | |
function text($text) | |
{ | |
# make sure no definitions are set | |
$this->DefinitionData = array(); | |
# standardize line breaks | |
$text = str_replace(array("\r\n", "\r"), "\n", $text); | |
# remove surrounding line breaks | |
$text = trim($text, "\n"); | |
# split text into lines | |
$lines = explode("\n", $text); | |
# iterate through lines to identify blocks | |
$markup = $this->lines($lines); | |
# trim line breaks | |
$markup = trim($markup, "\n"); | |
return $markup; | |
} | |
# | |
# Setters | |
# | |
function setBreaksEnabled($breaksEnabled) | |
{ | |
$this->breaksEnabled = $breaksEnabled; | |
return $this; | |
} | |
protected $breaksEnabled; | |
function setMarkupEscaped($markupEscaped) | |
{ | |
$this->markupEscaped = $markupEscaped; | |
return $this; | |
} | |
protected $markupEscaped; | |
function setUrlsLinked($urlsLinked) | |
{ | |
$this->urlsLinked = $urlsLinked; | |
return $this; | |
} | |
protected $urlsLinked = true; | |
# | |
# Lines | |
# | |
protected $BlockTypes = array( | |
'#' => array('Header'), | |
'*' => array('Rule', 'List'), | |
'+' => array('List'), | |
'-' => array('SetextHeader', 'Table', 'Rule', 'List'), | |
'0' => array('List'), | |
'1' => array('List'), | |
'2' => array('List'), | |
'3' => array('List'), | |
'4' => array('List'), | |
'5' => array('List'), | |
'6' => array('List'), | |
'7' => array('List'), | |
'8' => array('List'), | |
'9' => array('List'), | |
':' => array('Table'), | |
'<' => array('Comment', 'Markup'), | |
'=' => array('SetextHeader'), | |
'>' => array('Quote'), | |
'[' => array('Reference'), | |
'_' => array('Rule'), | |
'`' => array('FencedCode'), | |
'|' => array('Table'), | |
'~' => array('FencedCode'), | |
); | |
# ~ | |
protected $unmarkedBlockTypes = array( | |
'Code', | |
); | |
# | |
# Blocks | |
# | |
protected function lines(array $lines) | |
{ | |
$CurrentBlock = null; | |
foreach ($lines as $line) | |
{ | |
if (chop($line) === '') | |
{ | |
if (isset($CurrentBlock)) | |
{ | |
$CurrentBlock['interrupted'] = true; | |
} | |
continue; | |
} | |
if (strpos($line, "\t") !== false) | |
{ | |
$parts = explode("\t", $line); | |
$line = $parts[0]; | |
unset($parts[0]); | |
foreach ($parts as $part) | |
{ | |
$shortage = 4 - mb_strlen($line, 'utf-8') % 4; | |
$line .= str_repeat(' ', $shortage); | |
$line .= $part; | |
} | |
} | |
$indent = 0; | |
while (isset($line[$indent]) and $line[$indent] === ' ') | |
{ | |
$indent ++; | |
} | |
$text = $indent > 0 ? substr($line, $indent) : $line; | |
# ~ | |
$Line = array('body' => $line, 'indent' => $indent, 'text' => $text); | |
# ~ | |
if (isset($CurrentBlock['continuable'])) | |
{ | |
$Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); | |
if (isset($Block)) | |
{ | |
$CurrentBlock = $Block; | |
continue; | |
} | |
else | |
{ | |
if ($this->isBlockCompletable($CurrentBlock['type'])) | |
{ | |
$CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); | |
} | |
} | |
} | |
# ~ | |
$marker = $text[0]; | |
# ~ | |
$blockTypes = $this->unmarkedBlockTypes; | |
if (isset($this->BlockTypes[$marker])) | |
{ | |
foreach ($this->BlockTypes[$marker] as $blockType) | |
{ | |
$blockTypes []= $blockType; | |
} | |
} | |
# | |
# ~ | |
foreach ($blockTypes as $blockType) | |
{ | |
$Block = $this->{'block'.$blockType}($Line, $CurrentBlock); | |
if (isset($Block)) | |
{ | |
$Block['type'] = $blockType; | |
if ( ! isset($Block['identified'])) | |
{ | |
$Blocks []= $CurrentBlock; | |
$Block['identified'] = true; | |
} | |
if ($this->isBlockContinuable($blockType)) | |
{ | |
$Block['continuable'] = true; | |
} | |
$CurrentBlock = $Block; | |
continue 2; | |
} | |
} | |
# ~ | |
if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) | |
{ | |
$CurrentBlock['element']['text'] .= "\n".$text; | |
} | |
else | |
{ | |
$Blocks []= $CurrentBlock; | |
$CurrentBlock = $this->paragraph($Line); | |
$CurrentBlock['identified'] = true; | |
} | |
} | |
# ~ | |
if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) | |
{ | |
$CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); | |
} | |
# ~ | |
$Blocks []= $CurrentBlock; | |
unset($Blocks[0]); | |
# ~ | |
$markup = ''; | |
foreach ($Blocks as $Block) | |
{ | |
if (isset($Block['hidden'])) | |
{ | |
continue; | |
} | |
$markup .= "\n"; | |
$markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']); | |
} | |
$markup .= "\n"; | |
# ~ | |
return $markup; | |
} | |
protected function isBlockContinuable($Type) | |
{ | |
return method_exists($this, 'block'.$Type.'Continue'); | |
} | |
protected function isBlockCompletable($Type) | |
{ | |
return method_exists($this, 'block'.$Type.'Complete'); | |
} | |
# | |
# Code | |
protected function blockCode($Line, $Block = null) | |
{ | |
if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted'])) | |
{ | |
return; | |
} | |
if ($Line['indent'] >= 4) | |
{ | |
$text = substr($Line['body'], 4); | |
$Block = array( | |
'element' => array( | |
'name' => 'pre', | |
'handler' => 'element', | |
'text' => array( | |
'name' => 'code', | |
'text' => $text, | |
), | |
), | |
); | |
return $Block; | |
} | |
} | |
protected function blockCodeContinue($Line, $Block) | |
{ | |
if ($Line['indent'] >= 4) | |
{ | |
if (isset($Block['interrupted'])) | |
{ | |
$Block['element']['text']['text'] .= "\n"; | |
unset($Block['interrupted']); | |
} | |
$Block['element']['text']['text'] .= "\n"; | |
$text = substr($Line['body'], 4); | |
$Block['element']['text']['text'] .= $text; | |
return $Block; | |
} | |
} | |
protected function blockCodeComplete($Block) | |
{ | |
$text = $Block['element']['text']['text']; | |
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); | |
$Block['element']['text']['text'] = $text; | |
return $Block; | |
} | |
# | |
# Comment | |
protected function blockComment($Line) | |
{ | |
if ($this->markupEscaped) | |
{ | |
return; | |
} | |
if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') | |
{ | |
$Block = array( | |
'markup' => $Line['body'], | |
); | |
if (preg_match('/-->$/', $Line['text'])) | |
{ | |
$Block['closed'] = true; | |
} | |
return $Block; | |
} | |
} | |
protected function blockCommentContinue($Line, array $Block) | |
{ | |
if (isset($Block['closed'])) | |
{ | |
return; | |
} | |
$Block['markup'] .= "\n" . $Line['body']; | |
if (preg_match('/-->$/', $Line['text'])) | |
{ | |
$Block['closed'] = true; | |
} | |
return $Block; | |
} | |
# | |
# Fenced Code | |
protected function blockFencedCode($Line) | |
{ | |
if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches)) | |
{ | |
$Element = array( | |
'name' => 'code', | |
'text' => '', | |
); | |
if (isset($matches[1])) | |
{ | |
$class = 'language-'.$matches[1]; | |
$Element['attributes'] = array( | |
'class' => $class, | |
); | |
} | |
$Block = array( | |
'char' => $Line['text'][0], | |
'element' => array( | |
'name' => 'pre', | |
'handler' => 'element', | |
'text' => $Element, | |
), | |
); | |
return $Block; | |
} | |
} | |
protected function blockFencedCodeContinue($Line, $Block) | |
{ | |
if (isset($Block['complete'])) | |
{ | |
return; | |
} | |
if (isset($Block['interrupted'])) | |
{ | |
$Block['element']['text']['text'] .= "\n"; | |
unset($Block['interrupted']); | |
} | |
if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) | |
{ | |
$Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); | |
$Block['complete'] = true; | |
return $Block; | |
} | |
$Block['element']['text']['text'] .= "\n".$Line['body'];; | |
return $Block; | |
} | |
protected function blockFencedCodeComplete($Block) | |
{ | |
$text = $Block['element']['text']['text']; | |
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); | |
$Block['element']['text']['text'] = $text; | |
return $Block; | |
} | |
# | |
# Header | |
protected function blockHeader($Line) | |
{ | |
if (isset($Line['text'][1])) | |
{ | |
$level = 1; | |
while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') | |
{ | |
$level ++; | |
} | |
if ($level > 6) | |
{ | |
return; | |
} | |
$text = trim($Line['text'], '# '); | |
$Block = array( | |
'element' => array( | |
'name' => 'h' . min(6, $level), | |
'text' => $text, | |
'handler' => 'line', | |
), | |
); | |
return $Block; | |
} | |
} | |
# | |
# List | |
protected function blockList($Line) | |
{ | |
list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); | |
if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) | |
{ | |
$Block = array( | |
'indent' => $Line['indent'], | |
'pattern' => $pattern, | |
'element' => array( | |
'name' => $name, | |
'handler' => 'elements', | |
), | |
); | |
$Block['li'] = array( | |
'name' => 'li', | |
'handler' => 'li', | |
'text' => array( | |
$matches[2], | |
), | |
); | |
$Block['element']['text'] []= & $Block['li']; | |
return $Block; | |
} | |
} | |
protected function blockListContinue($Line, array $Block) | |
{ | |
if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) | |
{ | |
if (isset($Block['interrupted'])) | |
{ | |
$Block['li']['text'] []= ''; | |
unset($Block['interrupted']); | |
} | |
unset($Block['li']); | |
$text = isset($matches[1]) ? $matches[1] : ''; | |
$Block['li'] = array( | |
'name' => 'li', | |
'handler' => 'li', | |
'text' => array( | |
$text, | |
), | |
); | |
$Block['element']['text'] []= & $Block['li']; | |
return $Block; | |
} | |
if ($Line['text'][0] === '[' and $this->blockReference($Line)) | |
{ | |
return $Block; | |
} | |
if ( ! isset($Block['interrupted'])) | |
{ | |
$text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); | |
$Block['li']['text'] []= $text; | |
return $Block; | |
} | |
if ($Line['indent'] > 0) | |
{ | |
$Block['li']['text'] []= ''; | |
$text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); | |
$Block['li']['text'] []= $text; | |
unset($Block['interrupted']); | |
return $Block; | |
} | |
} | |
# | |
# Quote | |
protected function blockQuote($Line) | |
{ | |
if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) | |
{ | |
$Block = array( | |
'element' => array( | |
'name' => 'blockquote', | |
'handler' => 'lines', | |
'text' => (array) $matches[1], | |
), | |
); | |
return $Block; | |
} | |
} | |
protected function blockQuoteContinue($Line, array $Block) | |
{ | |
if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) | |
{ | |
if (isset($Block['interrupted'])) | |
{ | |
$Block['element']['text'] []= ''; | |
unset($Block['interrupted']); | |
} | |
$Block['element']['text'] []= $matches[1]; | |
return $Block; | |
} | |
if ( ! isset($Block['interrupted'])) | |
{ | |
$Block['element']['text'] []= $Line['text']; | |
return $Block; | |
} | |
} | |
# | |
# Rule | |
protected function blockRule($Line) | |
{ | |
if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) | |
{ | |
$Block = array( | |
'element' => array( | |
'name' => 'hr' | |
), | |
); | |
return $Block; | |
} | |
} | |
# | |
# Setext | |
protected function blockSetextHeader($Line, array $Block = null) | |
{ | |
if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) | |
{ | |
return; | |
} | |
if (chop($Line['text'], $Line['text'][0]) === '') | |
{ | |
$Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; | |
return $Block; | |
} | |
} | |
# | |
# Markup | |
protected function blockMarkup($Line) | |
{ | |
if ($this->markupEscaped) | |
{ | |
return; | |
} | |
if (preg_match('/^<(\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) | |
{ | |
$element = strtolower($matches[1]); | |
if (in_array($element, $this->textLevelElements)) | |
{ | |
return; | |
} | |
$Block = array( | |
'name' => $matches[1], | |
'depth' => 0, | |
'markup' => $Line['text'], | |
); | |
$length = strlen($matches[0]); | |
$remainder = substr($Line['text'], $length); | |
if (trim($remainder) === '') | |
{ | |
if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) | |
{ | |
$Block['closed'] = true; | |
$Block['void'] = true; | |
} | |
} | |
else | |
{ | |
if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) | |
{ | |
return; | |
} | |
if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) | |
{ | |
$Block['closed'] = true; | |
} | |
} | |
return $Block; | |
} | |
} | |
protected function blockMarkupContinue($Line, array $Block) | |
{ | |
if (isset($Block['closed'])) | |
{ | |
return; | |
} | |
if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open | |
{ | |
$Block['depth'] ++; | |
} | |
if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close | |
{ | |
if ($Block['depth'] > 0) | |
{ | |
$Block['depth'] --; | |
} | |
else | |
{ | |
$Block['closed'] = true; | |
} | |
} | |
if (isset($Block['interrupted'])) | |
{ | |
$Block['markup'] .= "\n"; | |
unset($Block['interrupted']); | |
} | |
$Block['markup'] .= "\n".$Line['body']; | |
return $Block; | |
} | |
# | |
# Reference | |
protected function blockReference($Line) | |
{ | |
if (preg_match('/^\[(.+?)\]:[ ]*<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) | |
{ | |
$id = strtolower($matches[1]); | |
$Data = array( | |
'url' => $matches[2], | |
'title' => null, | |
); | |
if (isset($matches[3])) | |
{ | |
$Data['title'] = $matches[3]; | |
} | |
$this->DefinitionData['Reference'][$id] = $Data; | |
$Block = array( | |
'hidden' => true, | |
); | |
return $Block; | |
} | |
} | |
# | |
# Table | |
protected function blockTable($Line, array $Block = null) | |
{ | |
if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) | |
{ | |
return; | |
} | |
if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') | |
{ | |
$alignments = array(); | |
$divider = $Line['text']; | |
$divider = trim($divider); | |
$divider = trim($divider, '|'); | |
$dividerCells = explode('|', $divider); | |
foreach ($dividerCells as $dividerCell) | |
{ | |
$dividerCell = trim($dividerCell); | |
if ($dividerCell === '') | |
{ | |
continue; | |
} | |
$alignment = null; | |
if ($dividerCell[0] === ':') | |
{ | |
$alignment = 'left'; | |
} | |
if (substr($dividerCell, - 1) === ':') | |
{ | |
$alignment = $alignment === 'left' ? 'center' : 'right'; | |
} | |
$alignments []= $alignment; | |
} | |
# ~ | |
$HeaderElements = array(); | |
$header = $Block['element']['text']; | |
$header = trim($header); | |
$header = trim($header, '|'); | |
$headerCells = explode('|', $header); | |
foreach ($headerCells as $index => $headerCell) | |
{ | |
$headerCell = trim($headerCell); | |
$HeaderElement = array( | |
'name' => 'th', | |
'text' => $headerCell, | |
'handler' => 'line', | |
); | |
if (isset($alignments[$index])) | |
{ | |
$alignment = $alignments[$index]; | |
$HeaderElement['attributes'] = array( | |
'style' => 'text-align: '.$alignment.';', | |
); | |
} | |
$HeaderElements []= $HeaderElement; | |
} | |
# ~ | |
$Block = array( | |
'alignments' => $alignments, | |
'identified' => true, | |
'element' => array( | |
'name' => 'table', | |
'handler' => 'elements', | |
), | |
); | |
$Block['element']['text'] []= array( | |
'name' => 'thead', | |
'handler' => 'elements', | |
); | |
$Block['element']['text'] []= array( | |
'name' => 'tbody', | |
'handler' => 'elements', | |
'text' => array(), | |
); | |
$Block['element']['text'][0]['text'] []= array( | |
'name' => 'tr', | |
'handler' => 'elements', | |
'text' => $HeaderElements, | |
); | |
return $Block; | |
} | |
} | |
protected function blockTableContinue($Line, array $Block) | |
{ | |
if (isset($Block['interrupted'])) | |
{ | |
return; | |
} | |
if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) | |
{ | |
$Elements = array(); | |
$row = $Line['text']; | |
$row = trim($row); | |
$row = trim($row, '|'); | |
preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); | |
foreach ($matches[0] as $index => $cell) | |
{ | |
$cell = trim($cell); | |
$Element = array( | |
'name' => 'td', | |
'handler' => 'line', | |
'text' => $cell, | |
); | |
if (isset($Block['alignments'][$index])) | |
{ | |
$Element['attributes'] = array( | |
'style' => 'text-align: '.$Block['alignments'][$index].';', | |
); | |
} | |
$Elements []= $Element; | |
} | |
$Element = array( | |
'name' => 'tr', | |
'handler' => 'elements', | |
'text' => $Elements, | |
); | |
$Block['element']['text'][1]['text'] []= $Element; | |
return $Block; | |
} | |
} | |
# | |
# ~ | |
# | |
protected function paragraph($Line) | |
{ | |
$Block = array( | |
'element' => array( | |
'name' => 'p', | |
'text' => $Line['text'], | |
'handler' => 'line', | |
), | |
); | |
return $Block; | |
} | |
# | |
# Inline Elements | |
# | |
protected $InlineTypes = array( | |
'"' => array('SpecialCharacter'), | |
'!' => array('Image'), | |
'&' => array('SpecialCharacter'), | |
'*' => array('Emphasis'), | |
':' => array('Url'), | |
'<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), | |
'>' => array('SpecialCharacter'), | |
'[' => array('Link'), | |
'_' => array('Emphasis'), | |
'`' => array('Code'), | |
'~' => array('Strikethrough'), | |
'\\' => array('EscapeSequence'), | |
); | |
# ~ | |
protected $inlineMarkerList = '!"*_&[:<>`~\\'; | |
# | |
# ~ | |
# | |
public function line($text) | |
{ | |
$markup = ''; | |
# $excerpt is based on the first occurrence of a marker | |
while ($excerpt = strpbrk($text, $this->inlineMarkerList)) | |
{ | |
$marker = $excerpt[0]; | |
$markerPosition = strpos($text, $marker); | |
$Excerpt = array('text' => $excerpt, 'context' => $text); | |
foreach ($this->InlineTypes[$marker] as $inlineType) | |
{ | |
$Inline = $this->{'inline'.$inlineType}($Excerpt); | |
if ( ! isset($Inline)) | |
{ | |
continue; | |
} | |
# makes sure that the inline belongs to "our" marker | |
if (isset($Inline['position']) and $Inline['position'] > $markerPosition) | |
{ | |
continue; | |
} | |
# sets a default inline position | |
if ( ! isset($Inline['position'])) | |
{ | |
$Inline['position'] = $markerPosition; | |
} | |
# the text that comes before the inline | |
$unmarkedText = substr($text, 0, $Inline['position']); | |
# compile the unmarked text | |
$markup .= $this->unmarkedText($unmarkedText); | |
# compile the inline | |
$markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); | |
# remove the examined text | |
$text = substr($text, $Inline['position'] + $Inline['extent']); | |
continue 2; | |
} | |
# the marker does not belong to an inline | |
$unmarkedText = substr($text, 0, $markerPosition + 1); | |
$markup .= $this->unmarkedText($unmarkedText); | |
$text = substr($text, $markerPosition + 1); | |
} | |
$markup .= $this->unmarkedText($text); | |
return $markup; | |
} | |
# | |
# ~ | |
# | |
protected function inlineCode($Excerpt) | |
{ | |
$marker = $Excerpt['text'][0]; | |
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $Excerpt['text'], $matches)) | |
{ | |
$text = $matches[2]; | |
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); | |
$text = preg_replace("/[ ]*\n/", ' ', $text); | |
return array( | |
'extent' => strlen($matches[0]), | |
'element' => array( | |
'name' => 'code', | |
'text' => $text, | |
), | |
); | |
} | |
} | |
protected function inlineEmailTag($Excerpt) | |
{ | |
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches)) | |
{ | |
$url = $matches[1]; | |
if ( ! isset($matches[2])) | |
{ | |
$url = 'mailto:' . $url; | |
} | |
return array( | |
'extent' => strlen($matches[0]), | |
'element' => array( | |
'name' => 'a', | |
'text' => $matches[1], | |
'attributes' => array( | |
'href' => $url, | |
), | |
), | |
); | |
} | |
} | |
protected function inlineEmphasis($Excerpt) | |
{ | |
if ( ! isset($Excerpt['text'][1])) | |
{ | |
return; | |
} | |
$marker = $Excerpt['text'][0]; | |
if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) | |
{ | |
$emphasis = 'strong'; | |
} | |
elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) | |
{ | |
$emphasis = 'em'; | |
} | |
else | |
{ | |
return; | |
} | |
return array( | |
'extent' => strlen($matches[0]), | |
'element' => array( | |
'name' => $emphasis, | |
'handler' => 'line', | |
'text' => $matches[1], | |
), | |
); | |
} | |
protected function inlineEscapeSequence($Excerpt) | |
{ | |
if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) | |
{ | |
return array( | |
'markup' => $Excerpt['text'][1], | |
'extent' => 2, | |
); | |
} | |
} | |
protected function inlineImage($Excerpt) | |
{ | |
if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') | |
{ | |
return; | |
} | |
$Excerpt['text']= substr($Excerpt['text'], 1); | |
$Link = $this->inlineLink($Excerpt); | |
if ($Link === null) | |
{ | |
return; | |
} | |
$Inline = array( | |
'extent' => $Link['extent'] + 1, | |
'element' => array( | |
'name' => 'img', | |
'attributes' => array( | |
'src' => $Link['element']['attributes']['href'], | |
'alt' => $Link['element']['text'], | |
), | |
), | |
); | |
$Inline['element']['attributes'] += $Link['element']['attributes']; | |
unset($Inline['element']['attributes']['href']); | |
return $Inline; | |
} | |
protected function inlineLink($Excerpt) | |
{ | |
$Element = array( | |
'name' => 'a', | |
'handler' => 'line', | |
'text' => null, | |
'attributes' => array( | |
'href' => null, | |
'title' => null, | |
), | |
); | |
$extent = 0; | |
$remainder = $Excerpt['text']; | |
if (preg_match('/\[((?:[^][]|(?R))*)\]/', $remainder, $matches)) | |
{ | |
$Element['text'] = $matches[1]; | |
$extent += strlen($matches[0]); | |
$remainder = substr($remainder, $extent); | |
} | |
else | |
{ | |
return; | |
} | |
if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches)) | |
{ | |
$Element['attributes']['href'] = $matches[1]; | |
if (isset($matches[2])) | |
{ | |
$Element['attributes']['title'] = substr($matches[2], 1, - 1); | |
} | |
$extent += strlen($matches[0]); | |
} | |
else | |
{ | |
if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) | |
{ | |
$definition = strlen($matches[1]) ? $matches[1] : $Element['text']; | |
$definition = strtolower($definition); | |
$extent += strlen($matches[0]); | |
} | |
else | |
{ | |
$definition = strtolower($Element['text']); | |
} | |
if ( ! isset($this->DefinitionData['Reference'][$definition])) | |
{ | |
return; | |
} | |
$Definition = $this->DefinitionData['Reference'][$definition]; | |
$Element['attributes']['href'] = $Definition['url']; | |
$Element['attributes']['title'] = $Definition['title']; | |
} | |
$Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']); | |
return array( | |
'extent' => $extent, | |
'element' => $Element, | |
); | |
} | |
protected function inlineMarkup($Excerpt) | |
{ | |
if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false) | |
{ | |
return; | |
} | |
if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w*[ ]*>/s', $Excerpt['text'], $matches)) | |
{ | |
return array( | |
'markup' => $matches[0], | |
'extent' => strlen($matches[0]), | |
); | |
} | |
if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?[^-])*-->/s', $Excerpt['text'], $matches)) | |
{ | |
return array( | |
'markup' => $matches[0], | |
'extent' => strlen($matches[0]), | |
); | |
} | |
if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches)) | |
{ | |
return array( | |
'markup' => $matches[0], | |
'extent' => strlen($matches[0]), | |
); | |
} | |
} | |
protected function inlineSpecialCharacter($Excerpt) | |
{ | |
if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) | |
{ | |
return array( | |
'markup' => '&', | |
'extent' => 1, | |
); | |
} | |
$SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); | |
if (isset($SpecialCharacter[$Excerpt['text'][0]])) | |
{ | |
return array( | |
'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', | |
'extent' => 1, | |
); | |
} | |
} | |
protected function inlineStrikethrough($Excerpt) | |
{ | |
if ( ! isset($Excerpt['text'][1])) | |
{ | |
return; | |
} | |
if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) | |
{ | |
return array( | |
'extent' => strlen($matches[0]), | |
'element' => array( | |
'name' => 'del', | |
'text' => $matches[1], | |
'handler' => 'line', | |
), | |
); | |
} | |
} | |
protected function inlineUrl($Excerpt) | |
{ | |
if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') | |
{ | |
return; | |
} | |
if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) | |
{ | |
$Inline = array( | |
'extent' => strlen($matches[0][0]), | |
'position' => $matches[0][1], | |
'element' => array( | |
'name' => 'a', | |
'text' => $matches[0][0], | |
'attributes' => array( | |
'href' => $matches[0][0], | |
), | |
), | |
); | |
return $Inline; | |
} | |
} | |
protected function inlineUrlTag($Excerpt) | |
{ | |
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) | |
{ | |
$url = str_replace(array('&', '<'), array('&', '<'), $matches[1]); | |
return array( | |
'extent' => strlen($matches[0]), | |
'element' => array( | |
'name' => 'a', | |
'text' => $url, | |
'attributes' => array( | |
'href' => $url, | |
), | |
), | |
); | |
} | |
} | |
# ~ | |
protected function unmarkedText($text) | |
{ | |
if ($this->breaksEnabled) | |
{ | |
$text = preg_replace('/[ ]*\n/', "<br />\n", $text); | |
} | |
else | |
{ | |
$text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "<br />\n", $text); | |
$text = str_replace(" \n", "\n", $text); | |
} | |
return $text; | |
} | |
# | |
# Handlers | |
# | |
protected function element(array $Element) | |
{ | |
$markup = '<'.$Element['name']; | |
if (isset($Element['attributes'])) | |
{ | |
foreach ($Element['attributes'] as $name => $value) | |
{ | |
if ($value === null) | |
{ | |
continue; | |
} | |
$markup .= ' '.$name.'="'.$value.'"'; | |
} | |
} | |
if (isset($Element['text'])) | |
{ | |
$markup .= '>'; | |
if (isset($Element['handler'])) | |
{ | |
$markup .= $this->{$Element['handler']}($Element['text']); | |
} | |
else | |
{ | |
$markup .= $Element['text']; | |
} | |
$markup .= '</'.$Element['name'].'>'; | |
} | |
else | |
{ | |
$markup .= ' />'; | |
} | |
return $markup; | |
} | |
protected function elements(array $Elements) | |
{ | |
$markup = ''; | |
foreach ($Elements as $Element) | |
{ | |
$markup .= "\n" . $this->element($Element); | |
} | |
$markup .= "\n"; | |
return $markup; | |
} | |
# ~ | |
protected function li($lines) | |
{ | |
$markup = $this->lines($lines); | |
$trimmedMarkup = trim($markup); | |
if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '<p>') | |
{ | |
$markup = $trimmedMarkup; | |
$markup = substr($markup, 3); | |
$position = strpos($markup, "</p>"); | |
$markup = substr_replace($markup, '', $position, 4); | |
} | |
return $markup; | |
} | |
# | |
# Deprecated Methods | |
# | |
function parse($text) | |
{ | |
$markup = $this->text($text); | |
return $markup; | |
} | |
# | |
# Static Methods | |
# | |
static function instance($name = 'default') | |
{ | |
if (isset(self::$instances[$name])) | |
{ | |
return self::$instances[$name]; | |
} | |
$instance = new static(); | |
self::$instances[$name] = $instance; | |
return $instance; | |
} | |
private static $instances = array(); | |
# | |
# Fields | |
# | |
protected $DefinitionData; | |
# | |
# Read-Only | |
protected $specialCharacters = array( | |
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', | |
); | |
protected $StrongRegex = array( | |
'*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', | |
'_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', | |
); | |
protected $EmRegex = array( | |
'*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', | |
'_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', | |
); | |
protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; | |
protected $voidElements = array( | |
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', | |
); | |
protected $textLevelElements = array( | |
'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', | |
'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', | |
'i', 'rp', 'del', 'code', 'strike', 'marquee', | |
'q', 'rt', 'ins', 'font', 'strong', | |
's', 'tt', 'sub', 'mark', | |
'u', 'xm', 'sup', 'nobr', | |
'var', 'ruby', | |
'wbr', 'span', | |
'time', | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment