Browse Source

BOM handling added

euromark 12 years ago
parent
commit
6d48fa4544

+ 5 - 7
Console/Command/ConvertShell.php

@@ -15,8 +15,6 @@ App::uses('AppShell', 'Console/Command');
  * 2011-11-04 ms
  * 2011-11-04 ms
  */
  */
 class ConvertShell extends AppShell {
 class ConvertShell extends AppShell {
-	public $uses = array();
-
 
 
 	/**
 	/**
 	 * predefined options
 	 * predefined options
@@ -43,9 +41,11 @@ class ConvertShell extends AppShell {
 		}
 		}
 	}
 	}
 
 
-
-
-
+	/**
+	 * ConvertShell::folder()
+	 *
+	 * @return void
+	 */
 	public function folder() {
 	public function folder() {
 		$this->out('Converting folder...');
 		$this->out('Converting folder...');
 
 
@@ -120,8 +120,6 @@ class ConvertShell extends AppShell {
 		}
 		}
 	}
 	}
 
 
-
-
 	/**
 	/**
 	 * get the option parser
 	 * get the option parser
 	 *
 	 *

+ 158 - 0
Console/Command/EncodingShell.php

@@ -0,0 +1,158 @@
+<?php
+
+App::uses('AppShell', 'Console/Command');
+
+/**
+ * Detect encoding or find invalid files (starting with BOM)
+ *
+ * @cakephp 2.x
+ * @author Mark Scherer
+ * @license MIT
+ * 2013-07-09 ms
+ */
+class EncodingShell extends AppShell {
+
+	/**
+	 * Files that need to be processed.
+	 *
+	 * @var array
+	 */
+	protected $_found = array();
+
+	/**
+	 * @return void
+	 */
+	public function startup() {
+		parent::startup();
+
+	}
+
+	/**
+	 * ConvertShell::folder()
+	 *
+	 * @return void
+	 */
+	public function folder() {
+		$folder = APP;
+		if (!empty($this->args)) {
+			$folder = array_shift($this->args);
+			$folder = realpath($folder);
+		}
+		if (empty($folder)) {
+			$this->error('Invalid dir', 'No valid dir given (either absolute or relative to APP)');
+		}
+		$this->out('Searching folder:');
+		$this->out($folder, 2);
+
+		$extensions = $this->params['ext'];
+		if (!$extensions) {
+			$extensions = 'php';
+		}
+
+		$this->_detect($folder, $extensions);
+		$this->out('Found: ' . count($this->_found));
+		if ($this->params['verbose']) {
+			foreach ($this->_found as $file) {
+				$this->out(' - ' . str_replace(APP, '/', $file));
+			}
+		}
+
+		$in = '';
+		if ($this->_found) {
+			$in = $this->in('Correct those files?', array('y', 'n'), 'n');
+		}
+		if ($in === 'y') {
+			if (empty($this->params['dry-run'])) {
+				foreach ($this->_found as $file) {
+					$content = file_get_contents($file);
+					$content = trim($content, b"\xEF\xBB\xBF");
+					file_put_contents($file, $content);
+				}
+			}
+			$this->out('Corrections applied');
+		}
+
+		$this->out('Done!');
+	}
+
+	/**
+	 * EncodingShell::_detect()
+	 *
+	 * @param string $path
+	 * @param array $extensions
+	 * @param array $excludes
+	 * @return void
+	 */
+	public function _detect($path, $extensions, $excludes = array()) {
+		$Iterator = new RegexIterator(
+			new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)),
+			'/^.+\.(' . $extensions . ')$/i',
+			RegexIterator::MATCH
+		);
+		foreach ($Iterator as $path) {
+			$fullPath = $path->__toString();
+			$continue = false;
+
+			foreach ($excludes as $exclude) {
+				if (strpos($fullPath, $exclude) === 0) {
+					$continue = true;
+					break;
+				}
+			}
+			if ($continue) {
+				continue;
+			}
+
+			if ($path->isDir()) {
+				continue;
+			}
+			if (strpos($fullPath, DS . '.') !== false) {
+				continue;
+			}
+			if (!empty($this->params['verbose'])) {
+				$this->out('Probing file: ' . str_replace(APP, '/', $fullPath));
+			}
+
+			$content = file_get_contents($fullPath);
+			if (strpos($content, b"\xEF\xBB\xBF") === 0) {
+				$this->_found[] = $fullPath;
+			}
+		}
+	}
+
+	/**
+	 * Get the option parser.
+	 *
+	 * @return ConsoleOptionParser
+	 */
+	public function getOptionParser() {
+		$subcommandParser = array(
+			'options' => array(
+				'ext' => array(
+					'short' => 'e',
+					'help' => __d('cake_console', 'Specify extensions [php|txt|...] - defaults to [php].'),
+					'default' => '',
+				),
+				'dry-run'=> array(
+					'short' => 'd',
+					'help' => __d('cake_console', 'Dry run the command, no files will actually be modified. Should be combined with verbose.'),
+					'boolean' => true
+				),
+				'exclude'=> array(
+					'short' => 'x',
+					'help' => __d('cake_console', 'exclude the following files'),
+					'boolean' => true,
+					'default' => ''
+				)
+			)
+		);
+
+		return parent::getOptionParser()
+			->description(__d('cake_console', 'The %sShell finds BOM files and can correct them.', $this->name))
+			->addSubcommand('folder', array(
+				'help' => __d('cake_console', 'Search and correct folder recursivly.'),
+				'parser' => $subcommandParser
+			));
+	}
+
+}

+ 22 - 0
Lib/Utility/FileLib.php

@@ -278,4 +278,26 @@ class FileLib extends File {
 		return $convertedArray;
 		return $convertedArray;
 	}
 	}
 
 
+	/**
+	 * Check if a blob string contains the BOM.
+	 * Useful for file_get_contents() + json_decode() that needs the BOM removed.
+	 *
+	 * @param string $content
+	 * @return boolean Success
+	 */
+	public static function hasByteOrderMark($content) {
+		return strpos($content, b"\xEF\xBB\xBF") === 0;
+	}
+
+	/**
+	 * Remove BOM from a blob string if detected.
+	 * Useful for file_get_contents() + json_decode() that needs the BOM removed.
+	 *
+	 * @param string $content
+	 * @return string Cleaned content
+	 */
+	public static function removeByteOrderMark($content) {
+		return trim($content, b"\xEF\xBB\xBF");
+	}
+
 }
 }

+ 38 - 0
Test/Case/Console/Command/EncodingShellTest.php

@@ -0,0 +1,38 @@
+<?php
+
+App::uses('EncodingShell', 'Tools.Console/Command');
+App::uses('MyCakeTestCase', 'Tools.TestSuite');
+
+class EncodingShellTest extends MyCakeTestCase {
+
+	public $EncodingShell;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->EncodingShell = new EncodingShell();
+		$this->EncodingShell->initialize();
+		$this->EncodingShell->startup();
+	}
+
+	public function testObject() {
+		$this->assertTrue(is_object($this->EncodingShell));
+		$this->assertInstanceOf('EncodingShell', $this->EncodingShell);
+	}
+
+	public function testFolder() {
+		$this->EncodingShell->params['ext'] = '';
+		$this->EncodingShell->params['verbose'] = false;
+		$this->EncodingShell->args[] = dirname(__FILE__);
+		$this->EncodingShell->folder();
+	}
+
+}
+
+class TestEncodingShell extends EncodingShell {
+
+	public function found() {
+		return $this->_found;
+	}
+
+}

+ 26 - 0
Test/Case/Lib/Utility/FileLibTest.php

@@ -240,6 +240,31 @@ class FileLibTest extends CakeTestCase {
 		$this->assertEquals($is, $expected);
 		$this->assertEquals($is, $expected);
 	}
 	}
 
 
+	/**
+	 * test BOM
+	 *
+	 * @return void
+	 */
+	public function testBOM() {
+		$folder = CakePlugin::path('Tools') . 'Test' . DS . 'test_files' . DS . 'txt' . DS;
+		$fileOK = $folder . 'ok.php';
+		$fileNOK = $folder. 'nok.php';
+		$result = FileLib::hasByteOrderMark(file_get_contents($fileOK));
+		$this->assertFalse($result);
+
+		$result = FileLib::hasByteOrderMark(file_get_contents($fileNOK));
+		$this->assertTrue($result);
+
+		$tmpFileNOK = TMP . 'nok.php';
+		copy($fileNOK, $tmpFileNOK);
+		$result = FileLib::removeByteOrderMark(file_get_contents($tmpFileNOK));
+		//file_put_contents($tmpFileNOK, $result);
+		//$result = FileLib::hasByteOrderMark(file_get_contents($tmpFileNOK));
+		$result = FileLib::hasByteOrderMark($result);
+		$this->assertFalse($result);
+		unlink($tmpFileNOK);
+	}
+
 	/** Helper Functions **/
 	/** Helper Functions **/
 
 
 	public function _printArrays($status, $is, $expected, $pre = null) {
 	public function _printArrays($status, $is, $expected, $pre = null) {
@@ -258,4 +283,5 @@ class FileLibTest extends CakeTestCase {
 			//pr($expected);
 			//pr($expected);
 		}
 		}
 	}
 	}
+
 }
 }