Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/include/txp_file.php - 1237 lines - 41244 bytes - Summary - Text - Print

Description: Files panel.

   1  <?php
   2  
   3  /*
   4   * Textpattern Content Management System
   5   * http://textpattern.com
   6   *
   7   * Copyright (C) 2004 Dean Allen
   8   * Copyright (C) 2016 The Textpattern Development Team
   9   *
  10   * "Mod File Upload" by Michael Manfre
  11   * http://manfre.net
  12   *
  13   * Copyright (C) 2004 Michael Manfre
  14   *
  15   * This file is part of Textpattern.
  16   *
  17   * Textpattern is free software; you can redistribute it and/or
  18   * modify it under the terms of the GNU General Public License
  19   * as published by the Free Software Foundation, version 2.
  20   *
  21   * Textpattern is distributed in the hope that it will be useful,
  22   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24   * GNU General Public License for more details.
  25   *
  26   * You should have received a copy of the GNU General Public License
  27   * along with Textpattern. If not, see <http://www.gnu.org/licenses/>.
  28   */
  29  
  30  /**
  31   * Files panel.
  32   *
  33   * @package Admin\File
  34   */
  35  
  36  use Textpattern\Validator\CategoryConstraint;
  37  use Textpattern\Validator\ChoiceConstraint;
  38  use Textpattern\Validator\Validator;
  39  use Textpattern\Search\Filter;
  40  
  41  if (!defined('txpinterface')) {
  42      die('txpinterface is undefined.');
  43  }
  44  
  45  $levels = array(
  46      1 => gTxt('private'),
  47      0 => gTxt('public'),
  48  );
  49  
  50  global $file_statuses;
  51  $file_statuses = status_list(true, array(STATUS_DRAFT, STATUS_STICKY));
  52  
  53  if ($event == 'file') {
  54      require_privs('file');
  55  
  56      global $all_file_cats, $all_file_authors;
  57      $all_file_cats = getTree('root', 'file');
  58      $all_file_authors = the_privileged('file.edit.own');
  59  
  60      $available_steps = array(
  61          'file_change_pageby' => true,
  62          'file_multi_edit'    => true,
  63          'file_edit'          => false,
  64          'file_insert'        => true,
  65          'file_list'          => false,
  66          'file_replace'       => true,
  67          'file_save'          => true,
  68          'file_create'        => true,
  69      );
  70  
  71      if ($step && bouncer($step, $available_steps)) {
  72          $step();
  73      } else {
  74          file_list();
  75      }
  76  }
  77  
  78  /**
  79   * The main panel listing all files.
  80   *
  81   * @param string|array $message The activity message
  82   */
  83  
  84  function file_list($message = '')
  85  {
  86      global $file_base_path, $file_statuses, $file_list_pageby, $txp_user, $event;
  87  
  88      pagetop(gTxt('tab_file'), $message);
  89  
  90      extract(gpsa(array(
  91          'page',
  92          'sort',
  93          'dir',
  94          'crit',
  95          'search_method',
  96      )));
  97  
  98      if ($sort === '') {
  99          $sort = get_pref('file_sort_column', 'filename');
 100      } else {
 101          if (!in_array($sort, array('id', 'description', 'category', 'title', 'downloads', 'author'))) {
 102              $sort = 'filename';
 103          }
 104  
 105          set_pref('file_sort_column', $sort, 'file', PREF_HIDDEN, '', 0, PREF_PRIVATE);
 106      }
 107  
 108      if ($dir === '') {
 109          $dir = get_pref('file_sort_dir', 'asc');
 110      } else {
 111          $dir = ($dir == 'asc') ? "asc" : "desc";
 112          set_pref('file_sort_dir', $dir, 'file', PREF_HIDDEN, '', 0, PREF_PRIVATE);
 113      }
 114  
 115      switch ($sort) {
 116          case 'id':
 117              $sort_sql = "txp_file.id $dir";
 118              break;
 119          case 'date':
 120              $sort_sql = "txp_file.created $dir, txp_file.id ASC";
 121              break;
 122          case 'category':
 123              $sort_sql = "txp_category.title $dir, txp_file.filename DESC";
 124              break;
 125          case 'title':
 126              $sort_sql = "txp_file.title $dir, txp_file.filename DESC";
 127              break;
 128          case 'downloads':
 129              $sort_sql = "txp_file.downloads $dir, txp_file.filename DESC";
 130              break;
 131          case 'author':
 132              $sort_sql = "txp_users.RealName $dir, txp_file.id ASC";
 133              break;
 134          default:
 135              $sort = 'filename';
 136              $sort_sql = "txp_file.filename $dir";
 137              break;
 138      }
 139  
 140      $switch_dir = ($dir == 'desc') ? 'asc' : 'desc';
 141  
 142      $search = new Filter($event,
 143          array(
 144              'id' => array(
 145                  'column' => 'txp_file.id',
 146                  'label'  => gTxt('ID'),
 147                  'type'   => 'integer',
 148              ),
 149              'filename' => array(
 150                  'column' => 'txp_file.filename',
 151                  'label'  => gTxt('file_name'),
 152              ),
 153              'title' => array(
 154                  'column' => 'txp_file.title',
 155                  'label'  => gTxt('title'),
 156              ),
 157              'description' => array(
 158                  'column' => 'txp_file.description',
 159                  'label'  => gTxt('description'),
 160              ),
 161              'category' => array(
 162                  'column' => array('txp_file.category', 'txp_category.title'),
 163                  'label'  => gTxt('file_category'),
 164              ),
 165              'status' => array(
 166                  'column' => array('txp_file.status'),
 167                  'label'  => gTxt('status'),
 168                  'type'   => 'boolean',
 169              ),
 170              'author' => array(
 171                  'column' => array('txp_file.author', 'txp_users.RealName'),
 172                  'label'  => gTxt('author'),
 173              ),
 174          )
 175      );
 176  
 177      $search->setAliases('status', $file_statuses);
 178  
 179      list($criteria, $crit, $search_method) = $search->getFilter(array(
 180              'id' => array('can_list' => true),
 181          ));
 182  
 183      $search_render_options = array(
 184          'placeholder' => 'search_files',
 185      );
 186  
 187      $sql_from =
 188          safe_pfx_j('txp_file')."
 189          LEFT JOIN ".safe_pfx_j('txp_category')." ON txp_category.name = txp_file.category AND txp_category.type = 'file'
 190          LEFT JOIN ".safe_pfx_j('txp_users')." ON txp_users.name = txp_file.author";
 191  
 192      if ($criteria === 1) {
 193          $total = safe_count('txp_file', $criteria);
 194      } else {
 195          $total = getThing("SELECT COUNT(*) FROM $sql_from WHERE $criteria");
 196      }
 197  
 198      echo n.'<div class="txp-layout">'.
 199          n.tag(
 200              hed(gTxt('tab_file'), 1, array('class' => 'txp-heading')),
 201              'div', array('class' => 'txp-layout-4col-alt')
 202          );
 203  
 204      $searchBlock =
 205          n.tag(
 206              $search->renderForm('file_list', $search_render_options),
 207              'div', array(
 208                  'class' => 'txp-layout-4col-3span',
 209                  'id'    => $event.'_control',
 210              )
 211          );
 212  
 213      $createBlock = array();
 214  
 215      if (!is_dir($file_base_path) || !is_writeable($file_base_path)) {
 216          $createBlock[] =
 217              graf(
 218                  span(null, array('class' => 'ui-icon ui-icon-alert')).' '.
 219                  gTxt('file_dir_not_writeable', array('{filedir}' => $file_base_path)),
 220                  array('class' => 'alert-block warning')
 221              );
 222      } elseif (has_privs('file.edit.own')) {
 223          $createBlock[] =
 224              n.tag_start('div', array('class' => 'txp-control-panel')).
 225              n.file_upload_form('upload_file', 'upload', 'file_insert', '', '', '', '');
 226  
 227          $existing_files = get_filenames();
 228  
 229          if ($existing_files) {
 230              $createBlock[] =
 231                  form(
 232                      eInput('file').
 233                      sInput('file_create').
 234                      tag(gTxt('existing_file'), 'label', array('for' => 'file-existing')).
 235                      selectInput('filename', $existing_files, '', 1, '', 'file-existing').
 236                      fInput('submit', '', gTxt('Create')),
 237                  '', '', 'post', 'assign-existing-form', '', 'assign_file');
 238          }
 239  
 240          $createBlock[] = tag_end('div');
 241      }
 242  
 243      $contentBlockStart = n.tag_start('div', array(
 244              'class' => 'txp-layout-1col',
 245              'id'    => $event.'_container',
 246          ));
 247  
 248      $createBlock = implode(n, $createBlock);
 249  
 250      if ($total < 1) {
 251          if ($criteria != 1) {
 252              echo $searchBlock.
 253                  $contentBlockStart.
 254                  $createBlock.
 255                  graf(
 256                      span(null, array('class' => 'ui-icon ui-icon-info')).' '.
 257                      gTxt('no_results_found'),
 258                      array('class' => 'alert-block information')
 259                  );
 260          } else {
 261              echo $contentBlockStart.
 262                  $createBlock.
 263                  graf(
 264                      span(null, array('class' => 'ui-icon ui-icon-info')).' '.
 265                      gTxt('no_files_recorded'),
 266                      array('class' => 'alert-block information')
 267                  );
 268          }
 269  
 270          echo n.tag_end('div'). // End of .txp-layout-1col.
 271              n.'</div>'; // End of .txp-layout.
 272  
 273          return;
 274      }
 275  
 276      $limit = max($file_list_pageby, 15);
 277  
 278      list($page, $offset, $numPages) = pager($total, $limit, $page);
 279  
 280      echo $searchBlock.$contentBlockStart.$createBlock;
 281  
 282      $rs = safe_query(
 283          "SELECT
 284              txp_file.id,
 285              txp_file.filename,
 286              txp_file.title,
 287              txp_file.category,
 288              txp_file.description,
 289              UNIX_TIMESTAMP(txp_file.created) AS uDate,
 290              txp_file.downloads,
 291              txp_file.status,
 292              txp_file.author,
 293              txp_users.RealName AS realname,
 294              txp_category.Title AS category_title
 295          FROM $sql_from WHERE $criteria ORDER BY $sort_sql LIMIT $offset, $limit"
 296      );
 297  
 298      if ($rs && numRows($rs)) {
 299          $show_authors = !has_single_author('txp_file');
 300  
 301          echo n.tag(
 302                  toggle_box('files_detail'), 'div', array('class' => 'txp-list-options')).
 303              n.tag_start('form', array(
 304                  'class'  => 'multi_edit_form',
 305                  'id'     => 'files_form',
 306                  'name'   => 'longform',
 307                  'method' => 'post',
 308                  'action' => 'index.php',
 309              )).
 310              n.tag_start('div', array('class' => 'txp-listtables')).
 311              n.tag_start('table', array('class' => 'txp-list')).
 312              n.tag_start('thead').
 313              tr(
 314                  hCell(
 315                      fInput('checkbox', 'select_all', 0, '', '', '', '', '', 'select_all'),
 316                          '', ' class="txp-list-col-multi-edit" scope="col" title="'.gTxt('toggle_all_selected').'"'
 317                  ).
 318                  column_head(
 319                      'ID', 'id', 'file', true, $switch_dir, $crit, $search_method,
 320                          (('id' == $sort) ? "$dir " : '').'txp-list-col-id'
 321                  ).
 322                  column_head(
 323                      'file_name', 'filename', 'file', true, $switch_dir, $crit, $search_method,
 324                          (('filename' == $sort) ? "$dir " : '').'txp-list-col-filename'
 325                  ).
 326                  column_head(
 327                      'title', 'title', 'file', true, $switch_dir, $crit, $search_method,
 328                          (('title' == $sort) ? "$dir " : '').'txp-list-col-title files_detail'
 329                  ).
 330                  column_head(
 331                      'date', 'date', 'image', true, $switch_dir, $crit, $search_method,
 332                          (('date' == $sort) ? "$dir " : '').'txp-list-col-created date files_detail'
 333                  ).
 334                  column_head(
 335                      'file_category', 'category', 'file', true, $switch_dir, $crit, $search_method,
 336                          (('category' == $sort) ? "$dir " : '').'txp-list-col-category category'
 337                  ).
 338                  hCell(gTxt(
 339                      'tags'), '', ' class="txp-list-col-tag-build files_detail" scope="col"'
 340                  ).
 341                  hCell(gTxt(
 342                      'status'), '', ' class="txp-list-col-status" scope="col"'
 343                  ).
 344                  hCell(gTxt(
 345                      'condition'), '', ' class="txp-list-col-condition" scope="col"'
 346                  ).
 347                  column_head(
 348                      'downloads', 'downloads', 'file', true, $switch_dir, $crit, $search_method,
 349                          (('downloads' == $sort) ? "$dir " : '').'txp-list-col-downloads'
 350                  ).
 351                  (
 352                      $show_authors
 353                      ? column_head('author', 'author', 'file', true, $switch_dir, $crit, $search_method,
 354                          (('author' == $sort) ? "$dir " : '').'txp-list-col-author name')
 355                      : ''
 356                  )
 357              ).
 358              n.tag_end('thead').
 359              n.tag_start('tbody');
 360  
 361          $validator = new Validator();
 362  
 363          while ($a = nextRow($rs)) {
 364              extract($a);
 365              $filename = sanitizeForFile($filename);
 366  
 367              $edit_url = array(
 368                  'event'         => 'file',
 369                  'step'          => 'file_edit',
 370                  'id'            => $id,
 371                  'sort'          => $sort,
 372                  'dir'           => $dir,
 373                  'page'          => $page,
 374                  'search_method' => $search_method,
 375                  'crit'          => $crit,
 376              );
 377  
 378              $tagName = 'file_download_link';
 379              $tag_url = array(
 380                  'id'          => $id,
 381                  'description' => $description,
 382                  'filename'    => $filename,
 383                  'step'        => 'build',
 384              );
 385  
 386              $file_exists = file_exists(build_file_path($file_base_path, $filename));
 387              $can_edit = has_privs('file.edit') || ($author === $txp_user && has_privs('file.edit.own'));
 388              $validator->setConstraints(array(new CategoryConstraint($category, array('type' => 'file'))));
 389  
 390              if ($validator->validate()) {
 391                  $vc = '';
 392              } else {
 393                  $vc = ' error';
 394              }
 395  
 396              if ($file_exists) {
 397                  $downloads = make_download_link($id, $downloads, $filename);
 398                  $condition = span(gTxt('file_status_ok'), array('class' => 'success'));
 399              } else {
 400                  $condition = span(gTxt('file_status_missing'), array('class' => 'error'));
 401              }
 402  
 403              if ($category) {
 404                  $category = span(txpspecialchars($category_title), array('title' => $category));
 405              }
 406  
 407              if ($can_edit) {
 408                  $name = href(txpspecialchars($filename), $edit_url, array('title' => gTxt('edit')));
 409              } else {
 410                  $name = txpspecialchars($filename);
 411              }
 412  
 413              if ($can_edit) {
 414                  $id_column = href($id, $edit_url, array('title' => gTxt('edit')));
 415                  $multi_edit = fInput('checkbox', 'selected[]', $id);
 416              } else {
 417                  $id_column = $id;
 418                  $multi_edit = '';
 419              }
 420  
 421              if ($file_exists) {
 422                  $id_column .= span(
 423                      sp.span('&#124;', array('role' => 'separator')).
 424                      sp.make_download_link($id, gTxt('download'), $filename),
 425                      array('class' => 'txp-option-link files_detail')
 426                  );
 427              }
 428  
 429              if (isset($file_statuses[$status])) {
 430                  $status = $file_statuses[$status];
 431              } else {
 432                  $status = span(gTxt('none'), array('class' => 'error'));
 433              }
 434  
 435              echo tr(
 436                  td(
 437                      $multi_edit, '', 'txp-list-col-multi-edit'
 438                  ).
 439                  hCell(
 440                      $id_column, '', array(
 441                          'class' => 'txp-list-col-id',
 442                          'scope' => 'row',
 443                      )
 444                  ).
 445                  td(
 446                      $name, '', 'txp-list-col-filename'
 447                  ).
 448                  td(
 449                      txpspecialchars($title), '', 'txp-list-col-title files_detail'
 450                  ).
 451                  td(
 452                      gTime($uDate), '', 'txp-list-col-created date files_detail'
 453                  ).
 454                  td(
 455                      $category, '', 'txp-list-col-category category'.$vc
 456                  ).
 457                  td(
 458                      popTag($tagName, 'Textile', array('type' => 'textile') + $tag_url).
 459                      sp.span('&#124;', array('role' => 'separator')).
 460                      sp.popTag($tagName, 'Textpattern', array('type' => 'textpattern') + $tag_url).
 461                      sp.span('&#124;', array('role' => 'separator')).
 462                      sp.popTag($tagName, 'HTML', array('type' => 'html') + $tag_url), '', 'txp-list-col-tag-build files_detail').
 463                  td(
 464                      $status, '', 'txp-list-col-status'
 465                  ).
 466                  td(
 467                      $condition, '', 'txp-list-col-condition'
 468                  ).
 469                  td(
 470                      $downloads, '', 'txp-list-col-downloads'
 471                  ).
 472                  (
 473                      $show_authors
 474                      ? td(span(txpspecialchars($realname), array('title' => $author)), '', 'txp-list-col-author name')
 475                      : ''
 476                  )
 477              );
 478          }
 479  
 480          echo
 481              n.tag_end('tbody').
 482              n.tag_end('table').
 483              n.tag_end('div'). // End of .txp-listtables.
 484              file_multiedit_form($page, $sort, $dir, $crit, $search_method).
 485              tInput().
 486              n.tag_end('form').
 487              n.tag_start('div', array(
 488                  'class' => 'txp-navigation',
 489                  'id'    => $event.'_navigation',
 490              )).
 491              pageby_form('file', $file_list_pageby).
 492              nav_form('file', $page, $numPages, $sort, $dir, $crit, $search_method, $total, $limit).
 493              n.tag_end('div');
 494      }
 495  
 496      echo n.tag_end('div'). // End of .txp-layout-1col.
 497          n.tag(
 498          null,
 499          'div', array(
 500              'class'      => 'txp-tagbuilder-content',
 501              'id'         => 'tagbuild_links',
 502              'aria-label' => gTxt('tagbuilder'),
 503              'title'      => gTxt('tagbuilder'),
 504          )).
 505          n.'</div>'; // End of .txp-layout.
 506  }
 507  
 508  // -------------------------------------------------------------
 509  
 510  function file_multiedit_form($page, $sort, $dir, $crit, $search_method)
 511  {
 512      global $file_statuses, $all_file_cats, $all_file_authors;
 513  
 514      $categories = $all_file_cats ? treeSelectInput('category', $all_file_cats, '') : '';
 515      $authors = $all_file_authors ? selectInput('author', $all_file_authors, '', true) : '';
 516      $status = selectInput('status', $file_statuses, '', true);
 517  
 518      $methods = array(
 519          'changecategory' => array('label' => gTxt('changecategory'), 'html' => $categories),
 520          'changeauthor'   => array('label' => gTxt('changeauthor'), 'html' => $authors),
 521          'changestatus'   => array('label' => gTxt('changestatus'), 'html' => $status),
 522          'changecount'    => array('label' => gTxt('reset_download_count')),
 523          'delete'         => gTxt('delete'),
 524      );
 525  
 526      if (!$categories) {
 527          unset($methods['changecategory']);
 528      }
 529  
 530      if (has_single_author('txp_file') || !has_privs('file.edit')) {
 531          unset($methods['changeauthor']);
 532      }
 533  
 534      if (!has_privs('file.delete.own') && !has_privs('file.delete')) {
 535          unset($methods['delete']);
 536      }
 537  
 538      return multi_edit($methods, 'file', 'file_multi_edit', $page, $sort, $dir, $crit, $search_method);
 539  }
 540  
 541  // -------------------------------------------------------------
 542  
 543  function file_multi_edit()
 544  {
 545      global $txp_user, $all_file_cats, $all_file_authors;
 546  
 547      // Empty entry to permit clearing the category.
 548      $categories = array('');
 549  
 550      foreach ($all_file_cats as $row) {
 551          $categories[] = $row['name'];
 552      }
 553  
 554      $selected = ps('selected');
 555  
 556      if (!$selected or !is_array($selected)) {
 557          return file_list();
 558      }
 559  
 560      $selected = array_map('assert_int', $selected);
 561      $method   = ps('edit_method');
 562      $changed  = array();
 563      $key = '';
 564  
 565      switch ($method) {
 566          case 'delete':
 567              return file_delete($selected);
 568              break;
 569          case 'changecategory':
 570              $val = ps('category');
 571              if (in_array($val, $categories)) {
 572                  $key = 'category';
 573              }
 574              break;
 575          case 'changeauthor':
 576              $val = ps('author');
 577              if (has_privs('file.edit') && in_array($val, $all_file_authors)) {
 578                  $key = 'author';
 579              }
 580              break;
 581          case 'changecount':
 582              $key = 'downloads';
 583              $val = 0;
 584              break;
 585          case 'changestatus' :
 586              $key = 'status';
 587              $val = ps('status');
 588  
 589              // Do not allow to be set to an empty value.
 590              if (!$val) {
 591                  $selected = array();
 592              }
 593              break;
 594          default:
 595              $key = '';
 596              $val = '';
 597              break;
 598      }
 599  
 600      if (!has_privs('file.edit')) {
 601          if (has_privs('file.edit.own')) {
 602              $selected = safe_column("id", 'txp_file', "id IN (".join(',', $selected).") AND author = '".doSlash($txp_user)."'");
 603          } else {
 604              $selected = array();
 605          }
 606      }
 607  
 608      if ($selected and $key) {
 609          foreach ($selected as $id) {
 610              if (safe_update('txp_file', "$key = '".doSlash($val)."'", "id = $id")) {
 611                  $changed[] = $id;
 612              }
 613          }
 614      }
 615  
 616      if ($changed) {
 617          update_lastmod('file_updated', $changed);
 618  
 619          return file_list(gTxt('file_updated', array('{name}' => join(', ', $changed))));
 620      }
 621  
 622      return file_list();
 623  }
 624  
 625  /**
 626   * Renders and outputs the file editor panel.
 627   *
 628   * @param string|array $message The activity message
 629   * @param int          $id      The file ID
 630   */
 631  
 632  function file_edit($message = '', $id = '')
 633  {
 634      global $file_base_path, $levels, $file_statuses, $txp_user, $event, $all_file_cats;
 635  
 636      extract(gpsa(array(
 637          'name',
 638          'title',
 639          'category',
 640          'permissions',
 641          'description',
 642          'sort',
 643          'dir',
 644          'page',
 645          'crit',
 646          'search_method',
 647          'publish_now',
 648      )));
 649  
 650      if (!$id) {
 651          $id = gps('id');
 652      }
 653  
 654      $id = assert_int($id);
 655      $rs = safe_row("*, UNIX_TIMESTAMP(created) AS created, UNIX_TIMESTAMP(modified) AS modified", 'txp_file', "id = $id");
 656  
 657      if ($rs) {
 658          extract($rs);
 659          $filename = sanitizeForFile($filename);
 660  
 661          if (!has_privs('file.edit') && !($author === $txp_user && has_privs('file.edit.own'))) {
 662              require_privs();
 663          }
 664  
 665          pagetop(gTxt('edit_file'), $message);
 666  
 667          if ($permissions == '') {
 668              $permissions = '-1';
 669          }
 670  
 671          if (!has_privs('file.publish') && $status >= STATUS_LIVE) {
 672              $status = STATUS_PENDING;
 673          }
 674  
 675          $file_exists = file_exists(build_file_path($file_base_path, $filename));
 676          $existing_files = get_filenames();
 677  
 678          $replace = ($file_exists)
 679              ? file_upload_form('replace_file', 'file_replace', 'file_replace', $id, 'file_replace', ' replace-file')
 680              : file_upload_form('file_relink', 'file_reassign', 'file_replace', $id, 'file_reassign', ' upload-file');
 681  
 682          $condition = span((($file_exists)
 683                  ? gTxt('file_status_ok')
 684                  : gTxt('file_status_missing')
 685              ), array('class' => (($file_exists) ? 'success' : 'error')));
 686  
 687          $downloadlink = ($file_exists) ? make_download_link($id, txpspecialchars($filename), $filename) : txpspecialchars($filename);
 688  
 689          $created =
 690              inputLabel(
 691                  'year',
 692                  tsi('year', '%Y', $rs['created'], '', 'year').
 693                  ' <span role="separator">/</span> '.
 694                  tsi('month', '%m', $rs['created'], '', 'month').
 695                  ' <span role="separator">/</span> '.
 696                  tsi('day', '%d', $rs['created'], '', 'day'),
 697                  'publish_date',
 698                  array('timestamp_file', 'instructions_file_date'),
 699                  array('class' => 'txp-form-field date posted')
 700              ).
 701              inputLabel(
 702                  'hour',
 703                  tsi('hour', '%H', $rs['created'], '', 'hour').
 704                  ' <span role="separator">:</span> '.
 705                  tsi('minute', '%M', $rs['created'], '', 'minute').
 706                  ' <span role="separator">:</span> '.
 707                  tsi('second', '%S', $rs['created'], '', 'second'),
 708                  'publish_time',
 709                  array('', 'instructions_file_time'),
 710                  array('class' => 'txp-form-field time posted')
 711              ).
 712              n.tag(
 713                  checkbox('publish_now', '1', $publish_now, '', 'publish_now').
 714                  n.tag(gTxt('set_to_now'), 'label', array('for' => 'publish_now')),
 715                  'div', array('class' => 'posted-now')
 716              );
 717  
 718          echo n.tag_start('div', array('class' => 'txp-edit')).
 719              hed(gTxt('edit_file'), 2).
 720              $replace.
 721              inputLabel(
 722                  'condition',
 723                  $condition,
 724                  '', '', array('class' => 'txp-form-field edit-file-condition')
 725              ).
 726              inputLabel(
 727                  'id',
 728                  $id,
 729                  'id', '', array('class' => 'txp-form-field edit-file-id')
 730              ).
 731              inputLabel(
 732                  'name',
 733                  $downloadlink,
 734                  '', '', array('class' => 'txp-form-field edit-file-name')
 735              ).
 736              inputLabel(
 737                  'download_count',
 738                  $downloads,
 739                  '', '', array('class' => 'txp-form-field edit-file-download-count')
 740              ).
 741              form(
 742                  (($file_exists)
 743                  ? inputLabel(
 744                          'file_status',
 745                          selectInput('status', $file_statuses, $status, false, '', 'file_status'),
 746                          'file_status', '', array('class' => 'txp-form-field edit-file-status')
 747                      ).
 748                      $created.
 749                      inputLabel(
 750                          'file_title',
 751                          fInput('text', 'title', $title, '', '', '', INPUT_REGULAR, '', 'file_title'),
 752                          'title', '', array('class' => 'txp-form-field edit-file-title')
 753                      ).
 754                      inputLabel(
 755                          'file_category',
 756                          event_category_popup('file', $category, 'file_category').
 757                          n.eLink('category', 'list', '', '', gTxt('edit'), '', '', '', 'txp-option-link'),
 758                          'file_category', '', array('class' => 'txp-form-field edit-file-category')
 759                      ).
 760  //                    inputLabel(
 761  //                        'perms',
 762  //                        selectInput('perms', $levels, $permissions),
 763  //                        'permissions'
 764  //                    ).
 765                      inputLabel(
 766                          'file_description',
 767                          '<textarea id="file_description" name="description" cols="'.INPUT_LARGE.'" rows="'.TEXTAREA_HEIGHT_SMALL.'">'.htmlspecialchars($description, ENT_NOQUOTES).'</textarea>',
 768                          'description', '', array('class' => 'txp-form-field txp-form-field-textarea edit-file-description')
 769                      ).
 770                      pluggable_ui('file_ui', 'extend_detail_form', '', $rs).
 771                      graf(
 772                          sLink('file', '', gTxt('cancel'), 'txp-button').
 773                          fInput('submit', '', gTxt('save'), 'publish'),
 774                          array('class' => 'txp-edit-actions')
 775                      ).
 776                      hInput('filename', $filename)
 777                  : (empty($existing_files)
 778                          ? ''
 779                          : gTxt('existing_file').selectInput('filename', $existing_files, '', 1)
 780                      ).
 781                      pluggable_ui('file_ui', 'extend_detail_form', '', $rs).
 782                      graf(
 783                          sLink('file', '', gTxt('cancel'), 'txp-button').
 784                          fInput('submit', '', gTxt('save'), 'publish'),
 785                          array('class' => 'txp-edit-actions')
 786                      ).
 787                      hInput('category', $category).
 788                      hInput('perms', ($permissions == '-1') ? '' : $permissions).
 789                      hInput('title', $title).
 790                      hInput('description', $description).
 791                      hInput('status', $status)
 792                  ).
 793                  eInput('file').
 794                  sInput('file_save').
 795                  hInput('id', $id).
 796                  hInput('sort', $sort).
 797                  hInput('dir', $dir).
 798                  hInput('page', $page).
 799                  hInput('crit', $crit).
 800                  hInput('search_method', $search_method),
 801              '', '', 'post', 'file-detail '.(($file_exists) ? '' : 'not-').'exists', '', (($file_exists) ? 'file_details' : 'assign_file')).
 802              n.tag_end('div');
 803      }
 804  }
 805  
 806  // -------------------------------------------------------------
 807  
 808  function file_db_add($filename, $category, $permissions, $description, $size, $title = '')
 809  {
 810      global $txp_user;
 811  
 812      if (trim($filename) === '') {
 813          return false;
 814      }
 815  
 816      $rs = safe_insert('txp_file',
 817          "filename = '$filename',
 818           title = '$title',
 819           category = '$category',
 820           permissions = '$permissions',
 821           description = '$description',
 822           size = '$size',
 823           created = NOW(),
 824           modified = NOW(),
 825           author = '".doSlash($txp_user)."'
 826      ");
 827  
 828      if ($rs) {
 829          $GLOBALS['ID'] = $rs;
 830          now('created', true);
 831  
 832          return $GLOBALS['ID'];
 833      }
 834  
 835      return false;
 836  }
 837  
 838  // -------------------------------------------------------------
 839  
 840  function file_create()
 841  {
 842      global $txp_user, $file_base_path;
 843  
 844      require_privs('file.edit.own');
 845  
 846      extract(doSlash(array_map('assert_string', gpsa(array(
 847          'filename',
 848          'title',
 849          'category',
 850          'permissions',
 851          'description',
 852      )))));
 853  
 854      $safe_filename = sanitizeForFile($filename);
 855      if ($safe_filename != $filename) {
 856          file_list(array(gTxt('invalid_filename'), E_ERROR));
 857  
 858          return;
 859      }
 860  
 861      $size = filesize(build_file_path($file_base_path, $safe_filename));
 862      $id = file_db_add($safe_filename, $category, $permissions, $description, $size, $title);
 863  
 864      if ($id === false) {
 865          file_list(array(gTxt('file_upload_failed').' (db_add)', E_ERROR));
 866      } else {
 867          $newpath = build_file_path($file_base_path, $safe_filename);
 868  
 869          if (is_file($newpath)) {
 870              file_set_perm($newpath);
 871              update_lastmod('file_created', compact('id', 'safe_filename', 'title', 'category', 'description'));
 872              now('created', true);
 873              file_list(gTxt('linked_to_file').' '.$safe_filename);
 874          } else {
 875              file_list(gTxt('file_not_found').' '.$safe_filename);
 876          }
 877      }
 878  }
 879  
 880  // -------------------------------------------------------------
 881  
 882  function file_insert()
 883  {
 884      global $txp_user, $file_base_path, $file_max_upload_size;
 885  
 886      require_privs('file.edit.own');
 887  
 888      extract(doSlash(array_map('assert_string', gpsa(array(
 889          'category',
 890          'title',
 891          'permissions',
 892          'description',
 893      )))));
 894  
 895      $name = file_get_uploaded_name();
 896      $file = file_get_uploaded();
 897  
 898      if ($file === false) {
 899          // Could not get uploaded file.
 900          file_list(array(gTxt('file_upload_failed')." $name - ".upload_get_errormsg($_FILES['thefile']['error']), E_ERROR));
 901  
 902          return;
 903      }
 904  
 905      $size = filesize($file);
 906      if ($file_max_upload_size < $size) {
 907          unlink($file);
 908          file_list(array(gTxt('file_upload_failed')." $name - ".upload_get_errormsg(UPLOAD_ERR_FORM_SIZE), E_ERROR));
 909  
 910          return;
 911      }
 912  
 913      $newname = sanitizeForFile($name);
 914      $newpath = build_file_path($file_base_path, $newname);
 915  
 916      if (!is_file($newpath) && !safe_count('txp_file', "filename = '".doSlash($newname)."'")) {
 917          $id = file_db_add(doSlash($newname), $category, $permissions, $description, $size, $title);
 918  
 919          if (!$id) {
 920              file_list(array(gTxt('file_upload_failed').' (db_add)', E_ERROR));
 921          } else {
 922              $id = assert_int($id);
 923  
 924              if (!shift_uploaded_file($file, $newpath)) {
 925                  safe_delete('txp_file', "id = $id");
 926                  safe_alter('txp_file', "auto_increment = $id");
 927  
 928                  if (isset($GLOBALS['ID'])) {
 929                      unset($GLOBALS['ID']);
 930                  }
 931  
 932                  file_list(array($newpath.' '.gTxt('upload_dir_perms'), E_ERROR));
 933                  // Clean up file.
 934              } else {
 935                  file_set_perm($newpath);
 936                  update_lastmod('file_uploaded', compact('id', 'newname', 'title', 'category', 'description'));
 937                  now('created', true);
 938                  file_edit(gTxt('file_uploaded', array('{name}' => $newname)), $id);
 939              }
 940          }
 941      } else {
 942          file_list(array(gTxt('file_already_exists', array('{name}' => $newname)), E_ERROR));
 943      }
 944  }
 945  
 946  // -------------------------------------------------------------
 947  
 948  function file_replace()
 949  {
 950      global $txp_user, $file_base_path;
 951  
 952      $id = assert_int(gps('id'));
 953      $rs = safe_row("filename, author", 'txp_file', "id = $id");
 954  
 955      if (!$rs) {
 956          file_list(array(messenger(gTxt('invalid_id'), $id), E_ERROR));
 957  
 958          return;
 959      }
 960  
 961      extract($rs);
 962      $filename = sanitizeForFile($filename);
 963  
 964      if (!has_privs('file.edit') && !($author === $txp_user && has_privs('file.edit.own'))) {
 965          require_privs();
 966      }
 967  
 968      $file = file_get_uploaded();
 969      $name = file_get_uploaded_name();
 970  
 971      if ($file === false) {
 972          // Could not get uploaded file.
 973          file_list(array(gTxt('file_upload_failed')." $name ".upload_get_errormsg($_FILES['thefile']['error']), E_ERROR));
 974  
 975          return;
 976      }
 977  
 978      if (!$filename) {
 979          file_list(array(gTxt('invalid_filename'), E_ERROR));
 980      } else {
 981          $newpath = build_file_path($file_base_path, $filename);
 982  
 983          if (is_file($newpath)) {
 984              rename($newpath, $newpath.'.tmp');
 985          }
 986  
 987          if (!shift_uploaded_file($file, $newpath)) {
 988              file_list(array($newpath.sp.gTxt('upload_dir_perms'), E_ERROR));
 989  
 990              // Rename tmp back.
 991              rename($newpath.'.tmp', $newpath);
 992  
 993              // Remove tmp upload.
 994              unlink($file);
 995          } else {
 996              file_set_perm($newpath);
 997              update_lastmod('file_replaced', compact('id', 'filename'));
 998              now('created', true);
 999  
1000              if ($size = filesize($newpath)) {
1001                  safe_update('txp_file', "size = $size, modified = NOW()", "id = $id");
1002              }
1003  
1004              file_edit(gTxt('file_uploaded', array('{name}' => $name)), $id);
1005  
1006              // Clean up old.
1007              if (is_file($newpath.'.tmp')) {
1008                  unlink($newpath.'.tmp');
1009              }
1010          }
1011      }
1012  }
1013  
1014  // -------------------------------------------------------------
1015  
1016  function file_save()
1017  {
1018      global $file_base_path, $file_statuses, $txp_user;
1019  
1020      $varray = array_map('assert_string', gpsa(array(
1021          'id',
1022          'category',
1023          'title',
1024          'description',
1025          'status',
1026          'publish_now',
1027          'year',
1028          'month',
1029          'day',
1030          'hour',
1031          'minute',
1032          'second',
1033      )));
1034  
1035      extract(doSlash($varray));
1036      $filename = $varray['filename'] = sanitizeForFile(gps('filename'));
1037  
1038      if ($filename == '') {
1039          file_list(array(gTxt('file_not_updated', array('{name}' => $filename)), E_ERROR));
1040  
1041          return;
1042      }
1043  
1044      $id = $varray['id'] = assert_int($id);
1045      $permissions = gps('perms');
1046  
1047      if (is_array($permissions)) {
1048          asort($permissions);
1049          $permissions = implode(",", $permissions);
1050      }
1051  
1052      $varray['permissions'] = $permissions;
1053      $perms = doSlash($permissions);
1054      $rs = safe_row("filename, author", 'txp_file', "id = $id");
1055  
1056      if (!has_privs('file.edit') && !($rs['author'] === $txp_user && has_privs('file.edit.own'))) {
1057          require_privs();
1058      }
1059  
1060      $old_filename = $varray['old_filename'] = sanitizeForFile($rs['filename']);
1061  
1062      if ($old_filename != false && strcmp($old_filename, $filename) != 0) {
1063          $old_path = build_file_path($file_base_path, $old_filename);
1064          $new_path = build_file_path($file_base_path, $filename);
1065  
1066          if (file_exists($old_path) && shift_uploaded_file($old_path, $new_path) === false) {
1067              file_list(array(gTxt('file_cannot_rename', array('{name}' => $filename)), E_ERROR));
1068  
1069              return;
1070          } else {
1071              file_set_perm($new_path);
1072          }
1073      }
1074  
1075      $created_ts = @safe_strtotime($year.'-'.$month.'-'.$day.' '.$hour.':'.$minute.':'.$second);
1076  
1077      if ($publish_now) {
1078          $created = "NOW()";
1079      } elseif ($created_ts > 0) {
1080          $created = "FROM_UNIXTIME('".$created_ts."')";
1081      } else {
1082          $created = '';
1083      }
1084  
1085      $size = filesize(build_file_path($file_base_path, $filename));
1086  
1087      $constraints = array(
1088          'category' => new CategoryConstraint(gps('category'), array('type' => 'file')),
1089          'status'   => new ChoiceConstraint(gps('status'), array('choices' => array_keys($file_statuses), 'message' => 'invalid_status')),
1090      );
1091      callback_event_ref('file_ui', 'validate_save', 0, $varray, $constraints);
1092      $validator = new Validator($constraints);
1093  
1094      $rs = $validator->validate() && safe_update('txp_file', "
1095          filename = '".doSlash($filename)."',
1096          title = '$title',
1097          category = '$category',
1098          permissions = '$perms',
1099          description = '$description',
1100          status = '$status',
1101          size = '$size',
1102          modified = NOW()"
1103          .($created ? ", created = $created" : ''), "id = $id");
1104  
1105      if (!$rs) {
1106          // Update failed, rollback name.
1107          if (isset($old_path) && shift_uploaded_file($new_path, $old_path) === false) {
1108              file_list(array(gTxt('file_unsynchronized', array('{name}' => $filename)), E_ERROR));
1109  
1110              return;
1111          } else {
1112              file_list(array(gTxt('file_not_updated', array('{name}' => $filename)), E_ERROR));
1113  
1114              return;
1115          }
1116      }
1117  
1118      update_lastmod('file_saved', compact('id', 'filename', 'title', 'category', 'description', 'status', 'size'));
1119      now('created', true);
1120      file_list(gTxt('file_updated', array('{name}' => $filename)));
1121  }
1122  
1123  // -------------------------------------------------------------
1124  
1125  function file_delete($ids = array())
1126  {
1127      global $file_base_path, $txp_user;
1128  
1129      $ids  = $ids ? array_map('assert_int', $ids) : array(assert_int(ps('id')));
1130  
1131      if (!has_privs('file.delete')) {
1132          if (has_privs('file.delete.own')) {
1133              $ids = safe_column("id", 'txp_file', "id IN (".join(',', $ids).") AND author = '".doSlash($txp_user)."'");
1134          } else {
1135              $ids = array();
1136          }
1137      }
1138  
1139      if (!empty($ids)) {
1140          $fail = array();
1141  
1142          $rs = safe_rows_start("id, filename", 'txp_file', "id IN (".join(',', $ids).")");
1143  
1144          if ($rs) {
1145              while ($a = nextRow($rs)) {
1146                  extract($a);
1147  
1148                  $filepath = build_file_path($file_base_path, $filename);
1149  
1150                  // Notify plugins of pending deletion, pass file's id and path.
1151                  callback_event('file_deleted', '', false, $id, $filepath);
1152  
1153                  $rsd = safe_delete('txp_file', "id = $id");
1154                  $ul = false;
1155  
1156                  if ($rsd && is_file($filepath)) {
1157                      $ul = unlink($filepath);
1158                  }
1159  
1160                  if (!$rsd or !$ul) {
1161                      $fail[] = $id;
1162                  }
1163              }
1164              if ($fail) {
1165                  file_list(array(messenger(gTxt('file_delete_failed'), join(', ', $fail)), E_ERROR));
1166  
1167                  return;
1168              } else {
1169                  update_lastmod('file_deleted', $ids);
1170                  now('created', true);
1171                  file_list(gTxt('file_deleted', array('{name}' => join(', ', $ids))));
1172  
1173                  return;
1174              }
1175          } else {
1176              file_list(array(messenger(gTxt('file_not_found'), join(', ', $ids), ''), E_ERROR));
1177  
1178              return;
1179          }
1180      }
1181      file_list();
1182  }
1183  
1184  // -------------------------------------------------------------
1185  
1186  function file_get_uploaded_name()
1187  {
1188      return $_FILES['thefile']['name'];
1189  }
1190  
1191  // -------------------------------------------------------------
1192  
1193  function file_get_uploaded()
1194  {
1195      return get_uploaded_file($_FILES['thefile']['tmp_name']);
1196  }
1197  
1198  // -------------------------------------------------------------
1199  
1200  function file_set_perm($file)
1201  {
1202      return @chmod($file, 0644);
1203  }
1204  
1205  /**
1206   * Renders a specific file upload form.
1207   *
1208   * @param  string       $label       File name label. May be empty
1209   * @param  string       $pophelp     Help item
1210   * @param  string       $step        Step
1211   * @param  string       $id          File id
1212   * @param  string       $label_id    HTML id attribute for the filename input element
1213   * @param  string       $class       HTML class attribute for the form element
1214   * @param  string|array $wraptag_val Tag to wrap the value / label in, or empty to omit
1215   * @return string HTML
1216   */
1217  
1218  function file_upload_form($label, $pophelp, $step, $id = '', $label_id = '', $class = '', $wraptag_val = array('div', 'div'))
1219  {
1220      global $file_max_upload_size;
1221  
1222      if (!$file_max_upload_size || intval($file_max_upload_size) == 0) {
1223          $file_max_upload_size = 2 * (1024 * 1024);
1224      }
1225  
1226      $max_file_size = (intval($file_max_upload_size) == 0) ? '' : intval($file_max_upload_size);
1227  
1228      return upload_form($label, $pophelp, $step, 'file', $id, $max_file_size, $label_id, $class, $wraptag_val);
1229  }
1230  
1231  // -------------------------------------------------------------
1232  
1233  function file_change_pageby()
1234  {
1235      event_change_pageby('file');
1236      file_list();
1237  }

title

Description

title

Description

title

Description

title

title

Body