339 lines
12 KiB
PHP
339 lines
12 KiB
PHP
<?php
|
|
//
|
|
// diagnose.summernote.php
|
|
//
|
|
// READ-ONLY diagnostic. Runs SELECT statements only -- it makes no changes to the
|
|
// database or to any file. Delete this file once the output has been captured.
|
|
//
|
|
// Purpose: determine why the Summernote toolbar on the Page Content dialog has no
|
|
// Gallery button and no image upload. table-edit.php only includes summernote.images.php
|
|
// when at least one dialog field is typed 'editbox':
|
|
//
|
|
// table-edit.php:78 if ($ftype == 'editbox') $SummerNoteRequired = true;
|
|
// table-edit.php:106 if ($SummerNoteRequired) include "form.includes/summernote-header.php";
|
|
// table-edit.php:725 if ($SummerNoteRequired) include "summernote.images.php";
|
|
//
|
|
// Field types live in the `_form_fields` table, column `action_fields_screen_field_type`,
|
|
// keyed by `action_name` (see table-edit.functions.php:40).
|
|
//
|
|
|
|
// include/globals.php refuses to run unless the calling page declares this first
|
|
// (see include/globals.php:3-9). Same guard ajax.imageUploader.php uses.
|
|
$ValidAccess = 2010;
|
|
|
|
// Match how the app's own endpoints open the session (ajax.imageUploader.php),
|
|
// but do not restart one that is already active.
|
|
if (session_status() != PHP_SESSION_ACTIVE) {
|
|
$sessionName = 'hotlunch';
|
|
session_name($sessionName);
|
|
session_start();
|
|
}
|
|
|
|
require_once("include/globals.php");
|
|
|
|
if (SessionActive() != 1 || ! UserLoggedIn()) {
|
|
echo "Not logged in -- sign in to the admin site first, then reload this page.";
|
|
exit();
|
|
}
|
|
|
|
// Admin-only, same permission set the page content module uses.
|
|
$AllowedUserTypes = array('SuperUser','System Administrator','Application Administrator','Communications Administrator');
|
|
if (checkPermission($AllowedUserTypes) != 1) {
|
|
echo "Access denied.";
|
|
exit();
|
|
}
|
|
|
|
header("Content-Type: text/plain; charset=utf-8");
|
|
|
|
function out($label, $value = null) {
|
|
if ($value === null) echo("$label\n");
|
|
else echo(str_pad($label, 34) . $value . "\n");
|
|
}
|
|
|
|
function rule($ch = '-') {
|
|
echo(str_repeat($ch, 78) . "\n");
|
|
}
|
|
|
|
rule('=');
|
|
out("SUMMERNOTE / GALLERY DIAGNOSTIC");
|
|
out("generated", date("Y-m-d H:i:s"));
|
|
rule('=');
|
|
echo("\n");
|
|
|
|
|
|
//
|
|
// 1. Which actions exist that look like the page content screen.
|
|
//
|
|
out("[1] CANDIDATE ACTIONS");
|
|
rule();
|
|
|
|
$actionNames = array();
|
|
$query = "SELECT DISTINCT action_name FROM _form_fields ORDER BY action_name";
|
|
$res = db_query($query);
|
|
if ($res && db_num_rows($res)) {
|
|
while ($row = db_fetch_assoc($res)) {
|
|
$name = $row['action_name'];
|
|
// Flag anything that plausibly refers to page/content editing.
|
|
if (stripos($name, 'content') !== false || stripos($name, 'page') !== false) {
|
|
$actionNames[] = $name;
|
|
out(" match", $name);
|
|
}
|
|
}
|
|
}
|
|
if (count($actionNames) == 0) {
|
|
out(" (no action_name matched 'content' or 'page')");
|
|
$actionNames[] = 'page-content'; // fall back to the expected name
|
|
}
|
|
echo("\n");
|
|
|
|
|
|
//
|
|
// 2. Full field listing for each candidate action. This is the answer:
|
|
// the `content` row's screen_field_type must be 'editbox'.
|
|
//
|
|
out("[2] FIELD DEFINITIONS (_form_fields)");
|
|
rule();
|
|
|
|
foreach ($actionNames as $actionName) {
|
|
$safeName = db_escape_string($actionName);
|
|
echo("\n");
|
|
out("ACTION: $actionName");
|
|
rule();
|
|
printf(" %-28s %-16s %-8s %s\n", "column_name", "field_type", "seq", "prompt");
|
|
printf(" %-28s %-16s %-8s %s\n", "---------------------------", "---------------", "-------", "----------------");
|
|
|
|
$summernoteRequired = false;
|
|
|
|
$query = "SELECT * FROM _form_fields WHERE action_name = '$safeName' ORDER BY sequence";
|
|
$res = db_query($query);
|
|
if (!$res || !db_num_rows($res)) {
|
|
out(" (no rows)");
|
|
continue;
|
|
}
|
|
|
|
while ($row = db_fetch_assoc($res)) {
|
|
$col = $row['action_fields_column_name'];
|
|
$ftype = $row['action_fields_screen_field_type'];
|
|
$seq = array_key_exists('sequence', $row) ? $row['sequence'] : '';
|
|
$prompt = array_key_exists('action_fields_field_prompt', $row) ? $row['action_fields_field_prompt'] : '';
|
|
|
|
if ($ftype == 'editbox') $summernoteRequired = true;
|
|
|
|
// Mark the row that controls whether Summernote loads.
|
|
$flag = ($col == 'content') ? ' <<< ' : ' ';
|
|
printf("%s%-28s %-16s %-8s %s\n", $flag, $col, $ftype, $seq, $prompt);
|
|
}
|
|
|
|
echo("\n");
|
|
out(" \$SummerNoteRequired would be", $summernoteRequired ? "TRUE (summernote.images.php IS included)"
|
|
: "FALSE (summernote.images.php is NOT included)");
|
|
}
|
|
echo("\n");
|
|
|
|
|
|
//
|
|
// 3. What field types are actually in use across the whole app. Confirms that
|
|
// 'editbox' is a valid value here and shows how many screens rely on it.
|
|
//
|
|
out("[3] FIELD TYPES IN USE (whole _form_fields table)");
|
|
rule();
|
|
|
|
$query = "SELECT action_fields_screen_field_type AS ftype, COUNT(*) AS num " .
|
|
"FROM _form_fields GROUP BY action_fields_screen_field_type ORDER BY num DESC";
|
|
$res = db_query($query);
|
|
if ($res && db_num_rows($res)) {
|
|
while ($row = db_fetch_assoc($res)) {
|
|
out(" " . $row['ftype'], $row['num']);
|
|
}
|
|
}
|
|
echo("\n");
|
|
|
|
|
|
//
|
|
// 4. Every action that already uses an editbox. These are the screens where the
|
|
// Gallery currently works -- useful as a known-good comparison.
|
|
//
|
|
out("[4] ACTIONS ALREADY USING 'editbox'");
|
|
rule();
|
|
|
|
$query = "SELECT action_name, action_fields_column_name FROM _form_fields " .
|
|
"WHERE action_fields_screen_field_type = 'editbox' ORDER BY action_name";
|
|
$res = db_query($query);
|
|
if ($res && db_num_rows($res)) {
|
|
while ($row = db_fetch_assoc($res)) {
|
|
out(" " . $row['action_name'], $row['action_fields_column_name']);
|
|
}
|
|
} else {
|
|
out(" (none -- no screen in this database uses editbox)");
|
|
}
|
|
echo("\n");
|
|
|
|
|
|
//
|
|
// 5. The action record itself. table-edit.php:53 reads action_include_js_file from
|
|
// here and includes "form.includes/<that file>" at line 700. The browser shows a
|
|
// working Summernote editor whose textarea has NO 'summernote' class and where
|
|
// none of summernote.images.php's symbols exist -- so some other script is
|
|
// initializing it. This is where that script is named.
|
|
//
|
|
out("[5] ACTION RECORD (the _form_actions / action table row)");
|
|
rule();
|
|
|
|
$foundActionTable = false;
|
|
foreach (array('_form_actions','_actions','form_actions') as $tbl) {
|
|
if (!db_tableExists($tbl)) continue;
|
|
$foundActionTable = true;
|
|
out(" table", $tbl);
|
|
echo("\n");
|
|
|
|
$query = "SELECT * FROM $tbl WHERE action_name = 'page-content'";
|
|
$res = db_query($query);
|
|
if ($res && db_num_rows($res)) {
|
|
while ($row = db_fetch_assoc($res)) {
|
|
foreach ($row as $k => $v) {
|
|
// Print every column; the js/dialog/form file columns are what matter.
|
|
out(" $k", $v);
|
|
}
|
|
}
|
|
} else {
|
|
out(" (no row for action_name = 'page-content')");
|
|
}
|
|
break;
|
|
}
|
|
if (!$foundActionTable) out(" (could not locate the actions table)");
|
|
echo("\n");
|
|
|
|
|
|
//
|
|
// 6. Which form.includes files actually exist on this server, so we can see whether
|
|
// the js file named above is present.
|
|
//
|
|
out("[6] form.includes/ DIRECTORY ON THIS SERVER");
|
|
rule();
|
|
|
|
if (is_dir("form.includes")) {
|
|
$files = scandir("form.includes");
|
|
foreach ($files as $f) {
|
|
if ($f == '.' || $f == '..') continue;
|
|
out(" " . $f, filesize("form.includes/$f") . " bytes");
|
|
}
|
|
} else {
|
|
out(" (form.includes/ not found)");
|
|
}
|
|
echo("\n");
|
|
|
|
|
|
//
|
|
// 7. Confirm whether summernote.images.php is actually reachable from this directory.
|
|
// #image-gallery-dialog was absent in the browser even though $SummerNoteRequired
|
|
// is TRUE, so either the include path fails or something exits before line 725.
|
|
//
|
|
out("[7] FILE PRESENCE");
|
|
rule();
|
|
|
|
foreach (array("summernote.images.php",
|
|
"form.includes/summernote-header.php",
|
|
"table-edit.php",
|
|
"summernote/summernote-lite.min.js",
|
|
"load.dynamic.php") as $f) {
|
|
out(" $f", is_file($f) ? (filesize($f) . " bytes") : "*** MISSING ***");
|
|
}
|
|
echo("\n");
|
|
|
|
// Does the deployed summernote.images.php contain the gallery markup?
|
|
if (is_file("summernote.images.php")) {
|
|
$sn = file_get_contents("summernote.images.php");
|
|
out(" contains image-gallery-dialog", (strpos($sn, "image-gallery-dialog") !== false) ? "YES" : "NO");
|
|
out(" contains loadGallery", (strpos($sn, "loadGallery") !== false) ? "YES" : "NO");
|
|
out(" file size", strlen($sn) . " bytes");
|
|
}
|
|
echo("\n");
|
|
|
|
|
|
//
|
|
// 8. WHERE AM I? The uploaded file's byte count is not changing, which means the
|
|
// running app may be loading a different copy than the one being uploaded.
|
|
// Resolve the real paths so we can see exactly which directory is live.
|
|
//
|
|
out("[8] PATH RESOLUTION");
|
|
rule();
|
|
|
|
out(" this script __FILE__", __FILE__);
|
|
out(" this script dir", dirname(__FILE__));
|
|
out(" getcwd()", getcwd());
|
|
out(" DOCUMENT_ROOT", isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : '(unset)');
|
|
out(" SCRIPT_FILENAME", isset($_SERVER['SCRIPT_FILENAME']) ? $_SERVER['SCRIPT_FILENAME'] : '(unset)');
|
|
out(" REQUEST_URI", isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '(unset)');
|
|
out(" \$AppDir (from globals)", isset($AppDir) ? $AppDir : '(unset)');
|
|
echo("\n");
|
|
|
|
// The include in table-edit.php is relative ("summernote.images.php"), so PHP resolves
|
|
// it against the include_path and the including file's directory. Show both, plus
|
|
// every copy of the file that exists anywhere obvious.
|
|
out(" include_path", ini_get('include_path'));
|
|
echo("\n");
|
|
|
|
out(" FILES NAMED summernote.images.php");
|
|
$searchDirs = array(dirname(__FILE__), getcwd());
|
|
if (isset($AppDir)) $searchDirs[] = $AppDir;
|
|
if (isset($_SERVER['DOCUMENT_ROOT'])) $searchDirs[] = $_SERVER['DOCUMENT_ROOT'];
|
|
$seen = array();
|
|
foreach ($searchDirs as $d) {
|
|
$p = rtrim($d, '/\\') . "/summernote.images.php";
|
|
$real = @realpath($p);
|
|
if ($real === false) { out(" $p", "(not found)"); continue; }
|
|
if (array_key_exists($real, $seen)) continue;
|
|
$seen[$real] = true;
|
|
out(" $real", filesize($real) . " bytes md5=" . md5_file($real));
|
|
}
|
|
echo("\n");
|
|
|
|
// Same question for table-edit.php -- if the live one differs from the local copy,
|
|
// the include line numbers I have been reading do not match what actually runs.
|
|
out(" TABLE-EDIT.PHP ACTUALLY PRESENT HERE");
|
|
$te = dirname(__FILE__) . "/table-edit.php";
|
|
if (is_file($te)) {
|
|
out(" path", realpath($te));
|
|
out(" size", filesize($te) . " bytes");
|
|
out(" md5", md5_file($te));
|
|
out(" modified", date("Y-m-d H:i:s", filemtime($te)));
|
|
|
|
// Show the actual include line, whatever number it lives on.
|
|
$lines = file($te);
|
|
foreach ($lines as $n => $line) {
|
|
if (strpos($line, 'summernote.images.php') !== false) {
|
|
out(" include at line " . ($n + 1), trim($line));
|
|
}
|
|
if (strpos($line, 'BuildDialogForm(') !== false) {
|
|
out(" BuildDialogForm at line " . ($n + 1), trim($line));
|
|
}
|
|
}
|
|
} else {
|
|
out(" (table-edit.php not in this directory)");
|
|
}
|
|
echo("\n");
|
|
|
|
// And the deployed summernote.images.php: fingerprint it so we can tell at a glance
|
|
// whether an upload actually landed.
|
|
out(" DEPLOYED summernote.images.php FINGERPRINT");
|
|
$sn = dirname(__FILE__) . "/summernote.images.php";
|
|
if (is_file($sn)) {
|
|
out(" path", realpath($sn));
|
|
out(" size", filesize($sn) . " bytes");
|
|
out(" md5", md5_file($sn));
|
|
out(" modified", date("Y-m-d H:i:s", filemtime($sn)));
|
|
$c = file_get_contents($sn);
|
|
// Markers unique to my edited version -- if these are absent, the upload never landed.
|
|
out(" has 'noteTarget' (my edit)", (strpos($c, 'noteTarget') !== false) ? "YES" : "NO");
|
|
out(" has 'note-dialog-open' (my edit)", (strpos($c, 'note-dialog-open') !== false) ? "YES" : "NO");
|
|
out(" has '_allowInteraction' (my edit)", (strpos($c, '_allowInteraction') !== false) ? "YES" : "NO");
|
|
}
|
|
echo("\n");
|
|
|
|
|
|
rule('=');
|
|
out("END OF DIAGNOSTIC -- no changes were made.");
|
|
rule('=');
|
|
|
|
?>
|