123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- <?php
- /**
- * $Id: ManifestTask.php 905 2010-10-05 16:28:03Z mrook $
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * This software consists of voluntary contributions made by many individuals
- * and is licensed under the LGPL. For more information please see
- * <http://phing.info>.
- */
- require_once "phing/Task.php";
- require_once 'phing/system/io/PhingFile.php';
- /**
- * ManifestTask
- *
- * Generates a simple Manifest file with optional checksums.
- *
- *
- * Manifest schema:
- * ...
- * path/to/file CHECKSUM [CHECKSUM2] [CHECKSUM3]
- * path/to/secondfile CHECKSUM [CHECKSUM2] [CHECKSUM3]
- * ...
- *
- * Example usage:
- * <manifest checksum="crc32" file="${dir_build}/Manifest">
- * <fileset refid="files_build" />
- * </manifest>
- *
- * <manifest checksum="md5,adler32,sha256" file="${dir_build}/Manifest">
- * <fileset refid="files_build" />
- * </manifest>
- *
- *
- *
- * @author David Persson <davidpersson at qeweurope dot org>
- * @package phing.tasks.ext
- * @version $Id: ManifestTask.php 905 2010-10-05 16:28:03Z mrook $
- * @since 2.3.1
- */
- class ManifestTask extends Task
- {
- var $taskname = 'manifest';
-
- /**
- * Action
- *
- * "w" for reading in files from fileSet
- * and writing manifest
- *
- * or
- *
- * "r" for reading in files from fileSet
- * and checking against manifest
- *
- * @var string "r" or "w"
- */
- private $action = 'w';
-
- /**
- * The target file passed in the buildfile.
- */
- private $destFile = null;
-
- /**
- * Holds filesets
- *
- * @var array An Array of objects
- */
- private $filesets = array();
- /**
- * Enable/Disable checksuming or/and select algorithm
- * true defaults to md5
- * false disables checksuming
- * string "md5,sha256,..." enables generation of multiple checksums
- * string "sha256" generates sha256 checksum only
- *
- * @var mixed
- */
- private $checksum = false;
-
- /**
- * A string used in hashing method
- *
- * @var string
- */
- private $salt = '';
-
- /**
- * Holds some data collected during runtime
- *
- * @var array
- */
- private $meta = array('totalFileCount' => 0,'totalFileSize' => 0);
-
-
- /**
- * The setter for the attribute "file"
- * This is where the manifest will be written to/read from
- *
- * @param string Path to readable file
- * @return void
- */
- public function setFile(PhingFile $file)
- {
- $this->file = $file;
- }
- /**
- * The setter for the attribute "checksum"
- *
- * @param mixed $mixed
- * @return void
- */
- public function setChecksum($mixed)
- {
- if(is_string($mixed)) {
- $data = array(strtolower($mixed));
- if(strpos($data[0],',')) {
- $data = explode(',',$mixed);
- }
-
- $this->checksum = $data;
-
- } elseif($mixed === true) {
- $this->checksum = array('md5');
-
- }
- }
-
- /**
- * The setter for the optional attribute "salt"
- *
- * @param string $string
- * @return void
- */
- public function setSalt($string)
- {
- $this->salt = $string;
- }
-
- /**
- * Nested creator, creates a FileSet for this task
- *
- * @access public
- * @return object The created fileset object
- */
- public function createFileSet()
- {
- $num = array_push($this->filesets, new FileSet());
- return $this->filesets[$num-1];
- }
- /**
- * The init method: Do init steps.
- */
- public function init()
- {
- // nothing to do here
- }
- /**
- * Delegate the work
- */
- public function main()
- {
- $this->validateAttributes();
-
- if($this->action == 'w') {
- $this->write();
-
- } elseif($this->action == 'r') {
- $this->read();
-
- }
- }
- /**
- * Creates Manifest file
- * Writes to $this->file
- *
- * @throws BuildException
- */
- private function write()
- {
- $project = $this->getProject();
-
- if(!touch($this->file->getPath())) {
- throw new BuildException("Unable to write to ".$this->file->getPath().".");
- }
- $this->log("Writing to " . $this->file->__toString(), Project::MSG_INFO);
- if(is_array($this->checksum)) {
- $this->log("Using " . implode(', ',$this->checksum)." for checksuming.", Project::MSG_INFO);
- }
-
- foreach($this->filesets as $fs) {
-
- $dir = $fs->getDir($this->project)->getPath();
- $ds = $fs->getDirectoryScanner($project);
- $fromDir = $fs->getDir($project);
- $srcFiles = $ds->getIncludedFiles();
- $srcDirs = $ds->getIncludedDirectories();
- foreach($ds->getIncludedFiles() as $file_path) {
- $line = $file_path;
- if($this->checksum) {
- foreach($this->checksum as $algo) {
- if(!$hash = $this->hashFile($dir.'/'.$file_path,$algo)) {
- throw new BuildException("Hashing $dir/$file_path with $algo failed!");
- }
- $line .= "\t".$hash;
- }
- }
- $line .= "\n";
- $manifest[] = $line;
- $this->log("Adding file ".$file_path,Project::MSG_VERBOSE);
- $this->meta['totalFileCount'] ++;
- $this->meta['totalFileSize'] += filesize($dir.'/'.$file_path);
- }
-
- }
-
- file_put_contents($this->file,$manifest);
-
- $this->log("Done. Total files: ".$this->meta['totalFileCount'].". Total file size: ".$this->meta['totalFileSize']." bytes.", Project::MSG_INFO);
- }
-
- /**
- * @todo implement
- */
- private function read()
- {
- throw new BuildException("Checking against manifest not yet supported.");
- }
-
- /**
- * Wrapper method for hash generation
- * Automatically selects extension
- * Falls back to built-in functions
- *
- * @link http://www.php.net/mhash
- * @link http://www.php.net/hash
- *
- * @param string $msg The string that should be hashed
- * @param string $algo Algorithm
- * @return mixed String on success, false if $algo is not available
- */
- private function hash($msg,$algo)
- {
- if(extension_loaded('hash')) {
- $algo = strtolower($algo);
-
- if(in_array($algo,hash_algos())) {
- return hash($algo,$this->salt.$msg);
- }
-
- }
-
- if(extension_loaded('mhash')) {
- $algo = strtoupper($algo);
-
- if(defined('MHASH_'.$algo)) {
- return mhash('MHASH_'.$algo,$this->salt.$msg);
-
- }
- }
-
- switch(strtolower($algo)) {
- case 'md5':
- return md5($this->salt.$msg);
- case 'crc32':
- return abs(crc32($this->salt.$msg));
- }
-
- return false;
- }
-
- /**
- * Hash a files contents
- * plus it's size an modification time
- *
- * @param string $file
- * @param string $algo
- * @return mixed String on success, false if $algo is not available
- */
- private function hashFile($file,$algo)
- {
- if(!file_exists($file)) {
- return false;
- }
-
- $msg = file_get_contents($file).filesize($file).filemtime($file);
-
- return $this->hash($msg,$algo);
- }
-
- /**
- * Validates attributes coming in from XML
- *
- * @access private
- * @return void
- * @throws BuildException
- */
- protected function validateAttributes()
- {
- if($this->action != 'r' && $this->action != 'w') {
- throw new BuildException("'action' attribute has non valid value. Use 'r' or 'w'");
- }
-
- if(empty($this->salt)) {
- $this->log("No salt provided. Specify one with the 'salt' attribute.", Project::MSG_WARN);
- }
-
- if (is_null($this->file) && count($this->filesets) === 0) {
- throw new BuildException("Specify at least sources and destination - a file or a fileset.");
- }
- if (!is_null($this->file) && $this->file->exists() && $this->file->isDirectory()) {
- throw new BuildException("Destination file cannot be a directory.");
- }
-
- }
- }
|