Textpattern | PHP Cross Reference | Content Management Systems |
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('|', 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('|', array('role' => 'separator')). 460 sp.popTag($tagName, 'Textpattern', array('type' => 'textpattern') + $tag_url). 461 sp.span('|', 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
Body
title
Description
Body
title
Description
Body
title
Body
title