1<?php 2 3namespace splitbrain\phpcli; 4 5/** 6 * Class Colors 7 * 8 * Handles color output on (Linux) terminals 9 * 10 * @author Andreas Gohr <andi@splitbrain.org> 11 * @license MIT 12 */ 13class Colors 14{ 15 // these constants make IDE autocompletion easier, but color names can also be passed as strings 16 const C_RESET = 'reset'; 17 const C_BLACK = 'black'; 18 const C_DARKGRAY = 'darkgray'; 19 const C_BLUE = 'blue'; 20 const C_LIGHTBLUE = 'lightblue'; 21 const C_GREEN = 'green'; 22 const C_LIGHTGREEN = 'lightgreen'; 23 const C_CYAN = 'cyan'; 24 const C_LIGHTCYAN = 'lightcyan'; 25 const C_RED = 'red'; 26 const C_LIGHTRED = 'lightred'; 27 const C_PURPLE = 'purple'; 28 const C_LIGHTPURPLE = 'lightpurple'; 29 const C_BROWN = 'brown'; 30 const C_YELLOW = 'yellow'; 31 const C_LIGHTGRAY = 'lightgray'; 32 const C_WHITE = 'white'; 33 34 /** @var array known color names */ 35 protected $colors = array( 36 self::C_RESET => "\33[0m", 37 self::C_BLACK => "\33[0;30m", 38 self::C_DARKGRAY => "\33[1;30m", 39 self::C_BLUE => "\33[0;34m", 40 self::C_LIGHTBLUE => "\33[1;34m", 41 self::C_GREEN => "\33[0;32m", 42 self::C_LIGHTGREEN => "\33[1;32m", 43 self::C_CYAN => "\33[0;36m", 44 self::C_LIGHTCYAN => "\33[1;36m", 45 self::C_RED => "\33[0;31m", 46 self::C_LIGHTRED => "\33[1;31m", 47 self::C_PURPLE => "\33[0;35m", 48 self::C_LIGHTPURPLE => "\33[1;35m", 49 self::C_BROWN => "\33[0;33m", 50 self::C_YELLOW => "\33[1;33m", 51 self::C_LIGHTGRAY => "\33[0;37m", 52 self::C_WHITE => "\33[1;37m", 53 ); 54 55 /** @var bool should colors be used? */ 56 protected $enabled = true; 57 58 /** 59 * Constructor 60 * 61 * Tries to disable colors for non-terminals 62 */ 63 public function __construct() 64 { 65 if (function_exists('posix_isatty') && !posix_isatty(STDOUT)) { 66 $this->enabled = false; 67 return; 68 } 69 if (!getenv('TERM')) { 70 $this->enabled = false; 71 return; 72 } 73 } 74 75 /** 76 * enable color output 77 */ 78 public function enable() 79 { 80 $this->enabled = true; 81 } 82 83 /** 84 * disable color output 85 */ 86 public function disable() 87 { 88 $this->enabled = false; 89 } 90 91 /** 92 * @return bool is color support enabled? 93 */ 94 public function isEnabled() 95 { 96 return $this->enabled; 97 } 98 99 /** 100 * Convenience function to print a line in a given color 101 * 102 * @param string $line the line to print, a new line is added automatically 103 * @param string $color one of the available color names 104 * @param resource $channel file descriptor to write to 105 * 106 * @throws Exception 107 */ 108 public function ptln($line, $color, $channel = STDOUT) 109 { 110 $this->set($color, $channel); 111 fwrite($channel, rtrim($line) . "\n"); 112 $this->reset($channel); 113 } 114 115 /** 116 * Returns the given text wrapped in the appropriate color and reset code 117 * 118 * @param string $text string to wrap 119 * @param string $color one of the available color names 120 * @return string the wrapped string 121 * @throws Exception 122 */ 123 public function wrap($text, $color) 124 { 125 return $this->getColorCode($color) . $text . $this->getColorCode('reset'); 126 } 127 128 /** 129 * Gets the appropriate terminal code for the given color 130 * 131 * @param string $color one of the available color names 132 * @return string color code 133 * @throws Exception 134 */ 135 public function getColorCode($color) 136 { 137 if (!$this->enabled) { 138 return ''; 139 } 140 if (!isset($this->colors[$color])) { 141 throw new Exception("No such color $color"); 142 } 143 144 return $this->colors[$color]; 145 } 146 147 /** 148 * Set the given color for consecutive output 149 * 150 * @param string $color one of the supported color names 151 * @param resource $channel file descriptor to write to 152 * @throws Exception 153 */ 154 public function set($color, $channel = STDOUT) 155 { 156 fwrite($channel, $this->getColorCode($color)); 157 } 158 159 /** 160 * reset the terminal color 161 * 162 * @param resource $channel file descriptor to write to 163 * 164 * @throws Exception 165 */ 166 public function reset($channel = STDOUT) 167 { 168 $this->set('reset', $channel); 169 } 170} 171