%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/infra/fusioninventory/inc/
Upload File :
Create Path :
Current File : //home/infra/fusioninventory/inc/deployfile.class.php

<?php

/**
 * FusionInventory
 *
 * Copyright (C) 2010-2023 by the FusionInventory Development Team.
 *
 * http://www.fusioninventory.org/
 * https://github.com/fusioninventory/fusioninventory-for-glpi
 * http://forge.fusioninventory.org/
 *
 * ------------------------------------------------------------------------
 *
 * LICENSE
 *
 * This file is part of FusionInventory project.
 *
 * FusionInventory is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FusionInventory is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with FusionInventory. If not, see <http://www.gnu.org/licenses/>.
 *
 * ------------------------------------------------------------------------
 *
 * This file is used to manage the files to deploy.
 *
 * ------------------------------------------------------------------------
 *
 * @package   FusionInventory
 * @author    Alexandre Delaunay
 * @author    David Durieux
 * @copyright Copyright (c) 2010-2023 FusionInventory team
 * @license   AGPL License 3.0 or (at your option) any later version
 *            http://www.gnu.org/licenses/agpl-3.0-standalone.html
 * @link      http://www.fusioninventory.org/
 * @link      https://github.com/fusioninventory/fusioninventory-for-glpi
 *
 */

if (!defined('GLPI_ROOT')) {
   die("Sorry. You can't access directly to this file");
}

/**
 * Manage the files to deploy.
 */
class PluginFusioninventoryDeployFile extends PluginFusioninventoryDeployPackageItem {

   public $shortname = 'files';
   public $json_name = 'associatedFiles';

   /**
    * The right name for this class
    *
    * @var string
    */
   static $rightname = 'plugin_fusioninventory_package';

   const REGISTRY_NO_DB_ENTRY = 0x1;
   const REGISTRY_NO_MANIFEST = 0x2;


   /**
    * Get the 2 types to add files
    *
    * @return array
    */
   function getTypes() {
      return [
         'Computer' => __("Upload from computer", 'fusioninventory'),
         'Server'   => __("Upload from server", 'fusioninventory')
      ];
   }


   /**
    * Display list of files
    *
    * @global array $CFG_GLPI
    * @param object $package PluginFusioninventoryDeployPackage instance
    * @param array $data array converted of 'json' field in DB where stored actions
    * @param string $rand unique element id used to identify/update an element
    */
   function displayList(PluginFusioninventoryDeployPackage $package, $data, $rand) {
      global $CFG_GLPI;

      $package_id = $package->getID();
      $canedit    = $package->canUpdateContent();

      // compute short shas to find the corresponding entries in database
      $short_shas = [];
      foreach ($data['jobs']['associatedFiles'] as $sha512) {
         $short_shas[] = substr($sha512, 0, 6);
      }
      // find corresponding file entries
      $files = $this->find(['shortsha512' => $short_shas]);
      // do a quick mapping between database id and short shas
      $files_mapping = [];
      foreach ($files as $file) {
         $files_mapping[$file['shortsha512']] = $file['id'];
      }

      echo "<table class='tab_cadrehov package_item_list' id='table_files_$rand'>";
      $i = 0;
      foreach ($data['jobs']['associatedFiles'] as $sha512) {
         $short_sha = substr($sha512, 0, 6);

         $fileregistry_error = 0;
         // check if the files is registered in database
         if (!array_key_exists($short_sha, $files_mapping)) {
            $fileregistry_error |= self::REGISTRY_NO_DB_ENTRY;
         }

         if (!$this->checkPresenceManifest($sha512)) {
            $fileregistry_error |= self::REGISTRY_NO_MANIFEST;
         }

         // get database entries
         if (!$fileregistry_error) {
            $file_id = $files_mapping[$short_sha];
            $file_name = $files[$file_id]['name'];
            $file_size = $files[$file_id]['filesize'];

            //mimetype icon
            if (isset($files[$file_id]['mimetype'])) {
               $file_mimetype =
                  str_replace('/', '__', $files[$file_id]['mimetype']);
            } else {
               $file_mimetype = null;
            }
         } else {
            // get file's name from what has been saved in json
            $file_name     = $data['associatedFiles'][$sha512]['name'];
            $file_size     = null;
            $file_mimetype = null;

         }
         $file_uncompress = $data['associatedFiles'][$sha512]['uncompress'];
         $file_p2p        = $data['associatedFiles'][$sha512]['p2p'];
         $file_p2p_retention_duration =
            $data['associatedFiles'][$sha512]['p2p-retention-duration'];

         // start new line
         $pics_path = Plugin::getWebDir('fusioninventory')."/pics/";
         echo Search::showNewLine(Search::HTML_OUTPUT, ($i%2));
         if ($canedit) {
            echo "<td class='control'>";
            Html::showCheckbox(['name' => 'file_entries['.$i.']', 'value' => 0]);
            echo "</td>";
         }
         echo "<td class='filename'>";
         if (!empty($file_mimetype)
                 && file_exists(PLUGIN_FUSIONINVENTORY_DIR."/pics/extensions/$file_mimetype.png")) {
            echo "<img src='".$pics_path."extensions/$file_mimetype.png' />";
         } else {
            echo "<img src='".$pics_path."extensions/documents.png' />";
         }

         //filename
         echo "&nbsp;";
         if ($canedit) {
            echo "<a class='edit'
                     onclick=\"edit_subtype('file', $package_id, $rand ,this)\">";
         }
         echo $file_name;
         if ($canedit) {
            echo "</a>";
         }

         //p2p icon
         if (isset($file_p2p)
            && $file_p2p != 0) {
            echo "<a title='".__('p2p', 'fusioninventory').", "
               .__("retention", 'fusioninventory')." : ".
               $file_p2p_retention_duration." ".
               __("Minute(s)", 'fusioninventory')."' class='more'>";
            echo "<img src='".$pics_path."p2p.png' />";
            echo "<sup>".$file_p2p_retention_duration."</sup>";
            echo "</a>";
         }

         //uncompress icon
         if (isset($file_uncompress)
                 && $file_uncompress != 0) {
            echo "<a title='".
                     __('uncompress', 'fusioninventory').
                     "' class='more'><img src='".
                     $pics_path.
                     "uncompress.png' /></a>";
         }
         //sha fingerprint
         $sha_status = "good";
         if ($fileregistry_error != 0) {
            $sha_status = "bad";
         }
         echo "<div class='fingerprint'>";
         echo "<div class='fingerprint_".$sha_status."'>".$sha512;
         if ($fileregistry_error & self::REGISTRY_NO_DB_ENTRY) {
            echo "<div class='fingerprint_badmsg'>".
                  __("This file is not correctly registered in database.")."<br/>".
                  __("You can fix it by uploading or selecting the good one.");
            echo "</div>";
         }
         if ($fileregistry_error & self::REGISTRY_NO_MANIFEST) {
            echo "<div class='fingerprint_badmsg'>".
                  __("This file doesn't have any manifest file associated.")."<br/>".
                  __("You must upload the file.");
            echo "</div>";
         }
         echo "</div>";
         echo "</div>";

         //filesize
         if (!$fileregistry_error) {
            echo "<div class='size'>";
            echo __('Size').": ".$this->processFilesize($file_size);
            echo "</div>";
         }
         echo "</td>";
         if ($canedit) {
            echo "<td class='rowhandler control' title='".
                    __('drag', 'fusioninventory').
                    "'><div class='drag row'></div></td>";
         }
         $i++;
      }
      if ($canedit) {
         echo "<tr><th>";
         echo Html::getCheckAllAsCheckbox("filesList$rand", mt_rand());
         echo "</th><th colspan='3' class='mark'></th></tr>";
      }
      echo "</table>";
      if ($canedit) {
         echo "&nbsp;&nbsp;<img src='".$CFG_GLPI["root_doc"]."/pics/arrow-left.png' alt=''>";
         echo "<input type='submit' name='delete' value=\"".
            __('Delete', 'fusioninventory')."\" class='submit'>";
      }
   }


   /**
    * Display different fields relative the file selected
    *
    * @global array $CFG_GLPI
    * @param array $config
    * @param array $request_data
    * @param string $rand unique element id used to identify/update an element
    * @param string $mode mode in use (create, edit...)
    * @return boolean
    */
   function displayAjaxValues($config, $request_data, $rand, $mode) {
      $fi_path = Plugin::getWebDir('fusioninventory');

      $pfDeployPackage = new PluginFusioninventoryDeployPackage();

      if (isset($request_data['packages_id'])) {
         $pfDeployPackage->getFromDB($request_data['packages_id']);
      } else {
         $pfDeployPackage->getEmpty();
      }

      $p2p                    = 0;
      $p2p_retention_duration = 0;
      $uncompress             = 0;

      if ($mode === self::CREATE) {
         $source = $request_data['value'];
         /**
          * No need to continue if there is no selected source
          */
         if ($source === '0') {
            return;
         }
      } else {
         $p2p                    = $config['data']['p2p'];
         $p2p_retention_duration = $config['data']['p2p-retention-duration'];
         $uncompress             = $config['data']['uncompress'];
      }

      echo "<table class='package_item'>";
      /*
       * Display file upload input only in 'create' mode
       */
      echo "<tr>";
      echo "<th>".__("File", 'fusioninventory')."</th>";
      echo "<td>";
      if ($mode === self::CREATE) {
         switch ($source) {

            case "Computer":
               echo "<input type='file' name='file' value='".
                  __("filename", 'fusioninventory')."' />";
               echo " <i>".$this->getMaxUploadSize()."</i>";
               break;

            case "Server":
               echo "<input type='text' name='filename' id='server_filename$rand'".
                  " style='width:500px;float:left' />";
               echo "<input type='button' class='submit' value='".__("Choose", 'fusioninventory').
                  "' onclick='fileModal$rand.show();' />";
               Ajax::createModalWindow("fileModal$rand",
                        $fi_path."/ajax/deployfilemodal.php",
                        ['title' => __('Select the file on server', 'fusioninventory'),
                        'extraparams' => [
                           'rand' => $rand
                        ]]);
               break;

         }
      } else {
         /*
          * Display only name in 'edit' mode
          */
         echo $config['data']['name'];
      }
      echo "</td>";
      echo "</tr>";

      echo "<tr>";
      echo "<th>".__("Uncompress", 'fusioninventory')."<img style='float:right' ".
         "src='".$fi_path."/pics/uncompress.png' /></th>";
      echo "<td>";
      Html::showCheckbox(['name' => 'uncompress', 'checked' => $uncompress]);
      echo "</td>";
      echo "</tr>";

      echo "<tr>";
      echo "<th>".__("P2P", 'fusioninventory').
              "<img style='float:right' src='".$fi_path.
              "/pics/p2p.png' /></th>";
      echo "<td>";
      Html::showCheckbox(['name' => 'p2p', 'checked' => $p2p]);
      echo "</td>";
      echo "</tr>";

      echo "<tr>";
      echo "<th>".__("retention", 'fusioninventory').
                  " - ".__("Minute(s)", 'fusioninventory')."</th>";
      echo "<td>";
      echo "<input type='number' name='p2p-retention-duration' value='$p2p_retention_duration' />";
      echo "</td>";
      echo "</tr>";

      $this->addOrSaveButton($pfDeployPackage, $mode);

      echo "</table>";
   }


   /**
    * Show files / directory on server.
    * This is used when get a file on the server
    *
    * @global array $CFG_GLPI
    * @param string $rand unique element id used to identify/update an element
    */
   static function showServerFileTree($rand) {
      echo "<script type='text/javascript'>";
      echo "Ext.Ajax.defaultHeaders = {'X-Glpi-Csrf-Token' : getAjaxCsrfToken()};";
      echo "var Tree_Category_Loader$rand = new Ext.tree.TreeLoader({
         dataUrl:'".Plugin::getWebDir('fusioninventory')."/ajax/serverfilestreesons.php'
      });";

      echo "var Tree_Category$rand = new Ext.tree.TreePanel({
         collapsible      : false,
         animCollapse     : false,
         border           : false,
         id               : 'tree_projectcategory$rand',
         el               : 'tree_projectcategory$rand',
         autoScroll       : true,
         animate          : false,
         enableDD         : true,
         containerScroll  : true,
         height           : 320,
         width            : 770,
         loader           : Tree_Category_Loader$rand,
         rootVisible      : false,
         listeners: {
            click: function(node, event) {
               if (node.leaf == true) {
                  console.log('server_filename$rand');
                  Ext.get('server_filename$rand').dom.value = node.id;
                  fileModal$rand.hide();
               }
            }
         }
      });";

      // SET the root node.
      echo "var Tree_Category_Root$rand = new Ext.tree.AsyncTreeNode({
         text     : '',
         draggable   : false,
         id    : '-1'                  // this IS the id of the startnode
      });
      Tree_Category$rand.setRootNode(Tree_Category_Root$rand);";

      // Render the tree.
      echo "Tree_Category$rand.render();
            Tree_Category_Root$rand.expand();";

      echo "</script>";

      echo "<div id='tree_projectcategory$rand' ></div>";
      echo "</div>";
   }


   /**
    * Get files / directories on server
    *
    * @param string $node
    */
   static function getServerFileTree($node) {

      $nodes            = [];
      $pfConfig         = new PluginFusioninventoryConfig();
      $dir              = $pfConfig->getValue('server_upload_path');
      $security_problem = false;
      if ($node != "-1") {
         if (strstr($node, "..")) {
            $security_problem = true;
         }
         $matches = [];
         preg_match("/^(".str_replace("/", "\/", $dir).")(.*)$/", $node, $matches);
         if (count($matches) != 3) {
            $security_problem = true;
         }
      }

      if (!$security_problem) {
         // leaf node
         if ($node != -1) {
            $dir = $node;
         }

         if (($handle = opendir($dir))) {
            $folders = $files = [];

            //list files in dir selected
            //we store folders and files separately to sort them alphabeticaly separatly
            while (false !== ($entry = readdir($handle))) {
               if ($entry != "." && $entry != "..") {
                  $filepath = $dir."/".$entry;
                  if (is_dir($filepath)) {
                     $folders[$filepath] = $entry;
                  } else {
                     $files[$filepath] = $entry;
                  }
               }
            }

            //sort folders and files (and maintain index association)
            asort($folders);
            asort($files);

            //add folders in json
            foreach ($folders as $filepath => $entry) {
               $path['text']      = $entry;
               $path['id']        = $filepath;
               $path['draggable'] = false;
               $path['leaf']      = false;
               $path['cls']       = 'folder';

               $nodes[] = $path;
            }

            //add files in json
            foreach ($files as $filepath => $entry) {
               $path['text']      = $entry;
               $path['id']        = $filepath;
               $path['draggable'] = false;
               $path['leaf']      = true;
               $path['cls']       = 'file';

               $nodes[] = $path;
            }
            closedir($handle);
         }
      }
      print json_encode($nodes);
   }


   /**
    * Add a new item in files of the package
    *
    * @param array $params list of fields with value of the file
    */
   function add_item($params) {
      switch ($params['filestype']) {

         case 'Server':
            return $this->uploadFileFromServer($params);
            break;

         default:
            return $this->uploadFileFromComputer($params);

      }
      return false;
   }


   /**
    * Remove an item
    *
    * @param array $params
    * @return boolean
    */
   function remove_item($params) {
      if (!isset($params['file_entries'])) {
         return false;
      }

      $shasToRemove = [];

      //get current order json
      $data = json_decode($this->getJson($params['packages_id']), true);

      $files = $data['jobs']['associatedFiles'];
      //remove selected checks

      foreach ($params['file_entries'] as $index => $checked) {
         if ($checked >= "1" || $checked == "on") {
            //get sha512
            $sha512 = $data['jobs']['associatedFiles'][$index];

            //remove file
            unset($files[$index]);
            unset($data['associatedFiles'][$sha512]);

            $shasToRemove[] = $sha512;
         }
      }
      $data['jobs']['associatedFiles'] = array_values($files);
      //update order
      $this->updateOrderJson($params['packages_id'], $data);

      //remove files in repo
      foreach ($shasToRemove as $sha512) {
         $this->removeFileInRepo($sha512);
      }

      return true;
   }


   /**
    * Save the item in files
    *
    * @param array $params list of fields with value of the file
    */
   function save_item($params) {
      //get current order json
      $data = json_decode($this->getJson($params['id']), true);

      //get sha512
      $sha512 = $data['jobs'][$this->json_name][$params['index']];

      //get file in json
      $file = $data[$this->json_name][$sha512];

      //remove value in json
      unset($data[$this->json_name][$sha512]);

      //update values
      $file['p2p']                    = isset($params['p2p']) ? $params['p2p'] : 0;
      $file['p2p-retention-duration'] = $params['p2p-retention-duration'];
      $file['uncompress']             = isset($params['uncompress']) ? $params['uncompress'] : 0;

      //add modified entry
      $data[$this->json_name][$sha512] = $file;

      //update order
      $this->updateOrderJson($params['id'], $data);
   }


   /**
    * Upload file from user computer
    *
    * @param array $params
    * @return boolean
    */
   function uploadFileFromComputer($params) {
      if (isset($params["id"])) {

         //file uploaded?
         if (isset($_FILES['file']['tmp_name'])
                 && !empty($_FILES['file']['tmp_name'])) {
            $file_tmp_name = $_FILES['file']['tmp_name'];
         }
         if (isset($_FILES['file']['name'])
                 && !empty($_FILES['file']['name'])) {
            $filename = $_FILES['file']['name'];
         }

         //file upload errors
         if (isset($_FILES['file']['error'])) {
            $error = true;
            switch ($_FILES['file']['error']) {

               case UPLOAD_ERR_INI_SIZE:
               case UPLOAD_ERR_FORM_SIZE:
                  $msg = __("Transfer error: the file size is too big", 'fusioninventory');
                  break;

               case UPLOAD_ERR_PARTIAL:
                  $msg = __("The uploaded file was only partially uploaded", 'fusioninventory');
                  break;

               case UPLOAD_ERR_NO_FILE:
                  $msg = __("No file was uploaded", 'fusioninventory');
                  break;

               case UPLOAD_ERR_NO_TMP_DIR:
                  $msg = __("Missing a temporary folder", 'fusioninventory');
                  break;

               case UPLOAD_ERR_CANT_WRITE:
                  $msg = __("Failed to write file to disk", 'fusioninventory');
                  break;

               case UPLOAD_ERR_EXTENSION:
                  $msg = __("PHP extension stopped the file upload", 'fusioninventory');
                  break;

               case UPLOAD_ERR_OK:
                  //no error, continue
                  $error = false;

            }
            if ($error) {
               Session::addMessageAfterRedirect($msg);
               return false;
            }
         }

         //prepare file data for insertion in repo
         $data = [
            'id'                     => $params['id'],
            'file_tmp_name'          => $file_tmp_name,
            'mime_type'              => $_FILES['file']['type'],
            'filesize'               => $_FILES['file']['size'],
            'filename'               => $filename,
            'p2p'                    => isset($params['p2p']) ? $params['p2p'] : 0,
            'uncompress'             => isset($params['uncompress']) ? $params['uncompress'] : 0,
            'p2p-retention-duration' => (is_numeric($params['p2p-retention-duration'])
                                          ? $params['p2p-retention-duration']: 0)
         ];

         //Add file in repo
         if ($filename && $this->addFileInRepo($data)) {
            Session::addMessageAfterRedirect(__('File saved!', 'fusioninventory'));
            return true;
         } else {
            Session::addMessageAfterRedirect(__('Failed to copy file', 'fusioninventory'));
            return false;
         }
      }
      Session::addMessageAfterRedirect(__('File missing', 'fusioninventory'));
      return false;
   }


   /**
    * Upload file from temp folder in server
    *
    * @param array $params
    * @return boolean
    */
   function uploadFileFromServer($params) {

      if (preg_match('/\.\./', $params['filename'])) {
         die;
      }

      if (isset($params["id"])) {
         $file_path = $params['filename'];
         $filename = basename($file_path);
         if (function_exists('finfo_open')
                 && ($finfo = finfo_open(FILEINFO_MIME))) {
            $mime_type = finfo_file($finfo, $file_path);
            finfo_close($finfo);

         } else if (function_exists('mime_content_type')) {
            $mime_type = mime_content_type($file_path);
         }
         $filesize = filesize($file_path);

         //prepare file data for insertion in repo
         $data = [
            'file_tmp_name' => $file_path,
            'mime_type'     => $mime_type,
            'filesize'      => $filesize,
            'filename'      => $filename,
            'p2p'           => isset($params['p2p']) ? $params['p2p'] : 0,
            'uncompress'    => isset($params['uncompress']) ? $params['uncompress'] : 0,
            'p2p-retention-duration' => (
               isset($params['p2p-retention-duration'])
               && is_numeric($params['p2p-retention-duration'])
                  ? $params['p2p-retention-duration']
                  : 0
            ),
            'id'            => $params['id']
         ];

         //Add file in repo
         if ($filename && $this->addFileInRepo($data)) {
            Session::addMessageAfterRedirect(__('File saved!', 'fusioninventory'));
            return true;
         } else {
            Session::addMessageAfterRedirect(__('Failed to copy file', 'fusioninventory'));
            return false;
         }
      }
      Session::addMessageAfterRedirect(__('File missing', 'fusioninventory'));
      return false;
   }


   /**
    * Get directories based on sha512
    *
    * @param string $sha512
    * @return string the directories based on sha512
    */
   function getDirBySha512 ($sha512) {
      $first = substr($sha512, 0, 1);
      $second = substr($sha512, 0, 2);

      return "$first/$second";
   }


   /**
   * Create a configuration request data
   *
   * @since 9.2
   */
   public function getItemConfig(PluginFusioninventoryDeployPackage $package, $request_data) {
      $element = $package->getSubElement($this->json_name, $request_data['index']);
      $config  = [];
      if ($element) {
         $config = [
            'hash' => $element,
            'data' => $package->getAssociatedFile($element),
         ];
      }
      return $config;
   }


   /**
    * Move uploaded file part in right/final directory
    *
    * @param string $filePath path of the file + filename
    * @param boolean $skip_creation
    * @return string
    */
   function registerFilepart ($filePath, $skip_creation = false) {
      $sha512 = hash_file('sha512', $filePath);

      if (!$skip_creation) {
         $dir = PLUGIN_FUSIONINVENTORY_REPOSITORY_DIR.$this->getDirBySha512($sha512);

         if (!file_exists ($dir)) {
            mkdir($dir, 0777, true);
         }
         copy ($filePath, $dir.'/'.$sha512);
      }
      return $sha512;
   }


   /**
    * Add file in the fusioninventory repository
    *
    * @param array $params
    * @return boolean
    */
   function addFileInRepo($params) {
      $filename      = addslashes($params['filename']);
      $file_tmp_name = $params['file_tmp_name'];
      $maxPartSize   = 1024*1024;
      $tmpFilepart   = tempnam(GLPI_PLUGIN_DOC_DIR."/fusioninventory/", "filestore");
      $sha512        = hash_file('sha512', $file_tmp_name);
      $short_sha512  = substr($sha512, 0, 6);

      $file_present_in_repo = false;
      if ($this->checkPresenceFile($sha512)) {
         $file_present_in_repo = true;
      }

      $file_present_in_db =
         (!empty($this->find(['shortsha512' => $short_sha512])));

      $new_entry = [
         'name'                   => $filename,
         'p2p'                    => $params['p2p'],
         'p2p-retention-duration' => $params['p2p-retention-duration'],
         'uncompress'             => $params['uncompress'],
      ];

      $fdIn = fopen($file_tmp_name, 'rb');
      if (!$fdIn) {
         return false;
      }

      $fdPart     = null;
      $multiparts = [];
      do {
         clearstatcache();
         if (file_exists($tmpFilepart)) {
            if (feof($fdIn) || filesize($tmpFilepart)>= $maxPartSize) {
               $part_sha512 = $this->registerFilepart($tmpFilepart,
                                                      $file_present_in_repo);
               unlink($tmpFilepart);

               $multiparts[] = $part_sha512;
            }
         }
         if (feof($fdIn)) {
            break;
         }

         $data   = fread($fdIn, 1024*1024);
         $fdPart = gzopen ($tmpFilepart, 'a');
         gzwrite($fdPart, $data, strlen($data));
         gzclose($fdPart);
      } while (1);

      //create manifest file
      if (!$file_present_in_repo) {
         $handle = fopen(
           PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$sha512, "w+"
         );
         if ($handle) {
            foreach ($multiparts as $sha) {
               fwrite($handle, $sha."\n");
            }
            fclose($handle);
         }
      }

      //TODO: Add a new files interface to list, create, manage entities and visibility
      // entity on a file is just anticipated and will be fully used later
      if (!$file_present_in_db) {
         $entry = [
            "name"         => $filename,
            "filesize"     => $params['filesize'],
            "mimetype"     => $params['mime_type'],
            "sha512"       => $sha512,
            "shortsha512"  => $short_sha512,
            "comments"     => "",
            "date_mod"     => date('Y-m-d H:i:s'),
            "entities_id"  => 0,
            "is_recursive" => 1
         ];
         $this->add($entry);
      }

      //get current package json
      $data = json_decode($this->getJson($params['id']), true);

      //add new entry
      $data[$this->json_name][$sha512] = $new_entry;
      if (!in_array($sha512, $data['jobs'][$this->json_name])) {
         $data['jobs'][$this->json_name][] = $sha512;
      }
      //update package
      $this->updateOrderJson($params['id'], $data);

      return true;
   }


   /**
    * Remove file from the repository
    *
    * @param string $sha512 sha512 of the file
    * @return boolean
    */
   function removeFileInRepo($sha512) {
      $pfDeployPackage = new PluginFusioninventoryDeployPackage();

      // try to find file in other packages
      $rows = $pfDeployPackage->find(
            ['json' => ['LIKE', '%'.substr($sha512, 0, 6 ).'%'],
             'json' => ['LIKE', '%'.$sha512.'%']]);

      //file found in other packages, do not remove parts in repo
      if (count($rows) > 0) {
         return false;
      }

      //get sha512 parts in manifest
      if (!file_exists(PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$sha512)) {
         return true;
      }
      $multiparts = file(PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$sha512);

      //parse all files part
      foreach ($multiparts as $part_sha512) {
         $firstdir = PLUGIN_FUSIONINVENTORY_REPOSITORY_DIR.substr($part_sha512, 0, 1)."/";
         $fulldir  = PLUGIN_FUSIONINVENTORY_REPOSITORY_DIR.$this->getDirBySha512($part_sha512).'/';

         //delete file parts
         unlink(trim($fulldir.$part_sha512));

         //delete folders if empty
         if (is_dir($fulldir)) {
            $count_second_folder = count(scandir($fulldir)) - 2;
            if ($count_second_folder === 0) {
               rmdir($fulldir);
            }
         }
         if (is_dir($firstdir)) {
            $count_first_folder = count(scandir($firstdir)) - 2; // -2 for . and ..
            if ($count_first_folder === 0) {
               rmdir($firstdir);
            }
         }
      }

      //remove manifest
      if (file_exists(PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$sha512)) {
         unlink(PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$sha512);
      }

      return true;
   }


   /**
    * Check if the manifest relative to the sha512 exist
    *
    * @param string $sha512 sha512 of the file
    * @return boolean
    */
   function checkPresenceManifest($sha512) {
      if (!file_exists(PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$sha512)) {
         return false;
      }
      return true;
   }


   /**
    * Check if the file relative to the sha512 exist
    *
    * @param string $sha512 sha512 of the file
    * @return boolean
    */
   function checkPresenceFile($sha512) {
      //Do not continue if the manifest is not found
      if (!$this->checkPresenceManifest($sha512)) {
         return false;
      }

      //Does the file needs to be created ?
      // Even if fileparts exists, we need to be sure
      // the manifest file is created
      $fileparts_ok = true;
      $fileparts_cnt = 0;
      $handle = fopen(PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$sha512, "r");
      if ($handle) {
         while (($buffer = fgets($handle)) !== false) {
            $fileparts_cnt++;
            $path = $this->getDirBySha512($buffer)."/".trim($buffer, "\n");
            //Check if the filepart exists
            if (!file_exists(PLUGIN_FUSIONINVENTORY_REPOSITORY_DIR.$path)) {
               $fileparts_ok = false;
               break;
            }
         }
         fclose($handle);
      }
      // Does the file is empty ?
      if ($fileparts_cnt == 0) {
         return false;
      }

      //Does the file needs to be replaced ?
      if (!$fileparts_ok) {
         return false;
      }
      //Nothing to do because the manifest and associated fileparts seems to be fine.
      return true;
   }


   /**
    * Get the maximum size the php can accept for upload file
    *
    * @return string
    */
   function getMaxUploadSize() {
      $max_upload   = (int)(ini_get('upload_max_filesize'));
      $max_post     = (int)(ini_get('post_max_size'));
      $memory_limit = (int)(ini_get('memory_limit'));

      return __('Max file size', 'fusioninventory')
         ." : ".min($max_upload, $max_post, $memory_limit).__('Mio', 'fusioninventory');
   }


   /**
    * List number of files not used in packages
    */
   function numberUnusedFiles() {
      echo "<table width='950' class='tab_cadre_fixe'>";

      echo "<tr>";
      echo "<th>";
      echo __('Unused file', 'fusioninventory');
      echo "</th>";
      echo "<th>";
      echo __('Size', 'fusioninventory');
      echo "</th>";
      echo "</tr>";

      $a_files = $this->find();
      foreach ($a_files as $data) {
         $cnt = countElementsInTable('glpi_plugin_fusioninventory_deploypackages',
            ['json' => ['LIKE', '%"' . $data['sha512'] . '"%']]);
         if ($cnt == 0) {
            echo "<tr class='tab_bg_1'>";
            echo "<td>";
            echo $data['name'];
            echo "</td>";
            echo "<td>";
            echo round($data['filesize'] / 1000000, 1)." ".__('Mio');
            echo "</td>";
            echo "</tr>";
         }
      }
      echo "</table>";
   }


   /**
    * Delete the files not used in packages
    */
   function deleteUnusedFiles() {
      $a_files = $this->find();
      foreach ($a_files as $data) {
         $cnt = countElementsInTable('glpi_plugin_fusioninventory_deploypackages',
            ['json' => ['LIKE', '%"' . $data['sha512'] . '"%']]);
         if ($cnt == 0) {
            $this->delete($data);
            $manifest_filename = PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$data['sha512'];
            if (file_exists($manifest_filename)) {
               $handle = @fopen($manifest_filename, "r");
               if ($handle) {
                  while (!feof($handle)) {
                     $buffer = trim(fgets($handle));
                     if ($buffer != '') {
                        $part_path = $this->getDirBySha512($buffer)."/".$buffer;
                        unlink(PLUGIN_FUSIONINVENTORY_REPOSITORY_DIR.$part_path);
                     }
                  }
                  fclose($handle);
               }
               unlink($manifest_filename);
            }
         }
      }
   }
}

Zerion Mini Shell 1.0