mirror of
https://github.com/itflow-org/itflow
synced 2026-08-27 09:55:12 +00:00
Remove thr web updater this is now either queued from the web or ran from the shell to update
This commit is contained in:
@@ -3,10 +3,11 @@
|
||||
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
|
||||
|
||||
/*
|
||||
* Hands the update to cron instead of running it in this request. scripts/update_cli.php
|
||||
* replaces the files this request is executing from and then applies the migrations that
|
||||
* came with them, which is not something to do half way through a page load - and on a host
|
||||
* where PHP cannot run external commands it is the only way to update the application at all.
|
||||
* Queueing is the ONLY way to update the application. There used to be an ?update handler
|
||||
* here that ran git pull (or a hard reset) inside this request; it is gone deliberately.
|
||||
* scripts/update_cli.php replaces the files this request is executing from and then applies
|
||||
* the migrations that came with them, which is not something to do half way through a page
|
||||
* load, and a host where PHP cannot run external commands could never do it at all.
|
||||
*
|
||||
* The row is written as well as the settings column: config_update_queued_at is what
|
||||
* cron/app_update.php acts on, and cron_job_run_now is what gets the dispatcher to look
|
||||
@@ -36,301 +37,6 @@ if (isset($_GET['queue_update'])) {
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['update'])) {
|
||||
|
||||
validateCSRFToken();
|
||||
|
||||
enforceAdminPermission();
|
||||
|
||||
// Reached only from buttons this install cannot draw without a shell, so anything
|
||||
// arriving here without one is a crafted request rather than somebody's mistake
|
||||
if (!shellCommandsAvailable()) {
|
||||
flashAlert("PHP on this server cannot run Git. Queue the update instead and cron will apply it.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
// git fetch downloads the latest from the remote without merging or rebasing anything.
|
||||
// The hard reset then throws away every local change and makes the working tree match
|
||||
// the tracked branch exactly.
|
||||
//
|
||||
// That reset used to name origin/master outright, so a force update on an install
|
||||
// tracking any other branch silently moved it onto master and discarded the code it was
|
||||
// actually running.
|
||||
if (isset($_GET['force_update']) == 1) {
|
||||
$remote_ref = escapeshellarg("origin/" . getRepoBranch());
|
||||
exec("git fetch --all");
|
||||
exec("git reset --hard $remote_ref");
|
||||
} else {
|
||||
exec("git pull");
|
||||
}
|
||||
//header("Location: post.php?update_db");
|
||||
|
||||
|
||||
// Send Telemetry if enabled during update
|
||||
if ($config_telemetry > 0 OR $config_telemetry = 2) {
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1");
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
|
||||
$company_name = escapeSql($row['company_name']);
|
||||
$website = escapeSql($row['company_website']);
|
||||
$city = escapeSql($row['company_city']);
|
||||
$state = escapeSql($row['company_state']);
|
||||
$country = escapeSql($row['company_country']);
|
||||
$currency = escapeSql($row['company_currency']);
|
||||
$current_version = exec("git rev-parse HEAD");
|
||||
|
||||
// Client Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('client_id') AS num FROM clients"));
|
||||
$client_count = $row['num'];
|
||||
|
||||
// Ticket Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('recurring_id') AS num FROM tickets"));
|
||||
$ticket_count = $row['num'];
|
||||
|
||||
// Recurring Ticket Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_ticket_id') AS num FROM recurring_tickets"));
|
||||
$recurring_ticket_count = $row['num'];
|
||||
|
||||
// Calendar Event Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('event_id') AS num FROM calendar_events"));
|
||||
$calendar_event_count = $row['num'];
|
||||
|
||||
// Quote Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('quote_id') AS num FROM quotes"));
|
||||
$quote_count = $row['num'];
|
||||
|
||||
// Invoice Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('invoice_id') AS num FROM invoices"));
|
||||
$invoice_count = $row['num'];
|
||||
|
||||
// Revenue Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('revenue_id') AS num FROM revenues"));
|
||||
$revenue_count = $row['num'];
|
||||
|
||||
// Recurring Invoice Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('recurring_invoice_id') AS num FROM recurring_invoices"));
|
||||
$recurring_invoice_count = $row['num'];
|
||||
|
||||
// Account Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('account_id') AS num FROM accounts"));
|
||||
$account_count = $row['num'];
|
||||
|
||||
// Tax Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('tax_id') AS num FROM taxes"));
|
||||
$tax_count = $row['num'];
|
||||
|
||||
// Product Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('product_id') AS num FROM products"));
|
||||
$product_count = $row['num'];
|
||||
|
||||
// Payment Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('payment_id') AS num FROM payments WHERE payment_invoice_id > 0"));
|
||||
$payment_count = $row['num'];
|
||||
|
||||
// Company Vendor Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('vendor_id') AS num FROM vendors WHERE vendor_client_id = 0"));
|
||||
$company_vendor_count = $row['num'];
|
||||
|
||||
// Expense Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('expense_id') AS num FROM expenses WHERE expense_vendor_id > 0"));
|
||||
$expense_count = $row['num'];
|
||||
|
||||
// Trip Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('trip_id') AS num FROM trips"));
|
||||
$trip_count = $row['num'];
|
||||
|
||||
// Transfer Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('transfer_id') AS num FROM transfers"));
|
||||
$transfer_count = $row['num'];
|
||||
|
||||
// Contact Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('contact_id') AS num FROM contacts"));
|
||||
$contact_count = $row['num'];
|
||||
|
||||
// Location Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('location_id') AS num FROM locations"));
|
||||
$location_count = $row['num'];
|
||||
|
||||
// Asset Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('asset_id') AS num FROM assets"));
|
||||
$asset_count = $row['num'];
|
||||
|
||||
// Software Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('software_id') AS num FROM software"));
|
||||
$software_count = $row['num'];
|
||||
|
||||
// Software Template Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('software_template_id') AS num FROM software_templates"));
|
||||
$software_template_count = $row['num'];
|
||||
|
||||
// Password Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('credential_id') AS num FROM credentials"));
|
||||
$credential_count = $row['num'];
|
||||
|
||||
// Network Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('network_id') AS num FROM networks"));
|
||||
$network_count = $row['num'];
|
||||
|
||||
// Certificate Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('certificate_id') AS num FROM certificates"));
|
||||
$certificate_count = $row['num'];
|
||||
|
||||
// Domain Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('domain_id') AS num FROM domains"));
|
||||
$domain_count = $row['num'];
|
||||
|
||||
// Service Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('service_id') AS num FROM services"));
|
||||
$service_count = $row['num'];
|
||||
|
||||
// Client Vendor Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('vendor_id') AS num FROM vendors WHERE vendor_client_id > 0"));
|
||||
$client_vendor_count = $row['num'];
|
||||
|
||||
// Vendor Template Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('vendor_template_id') AS num FROM vendor_templates"));
|
||||
$vendor_template_count = $row['num'];
|
||||
|
||||
// File Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('file_id') AS num FROM files"));
|
||||
$file_count = $row['num'];
|
||||
|
||||
// Document Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('document_id') AS num FROM documents"));
|
||||
$document_count = $row['num'];
|
||||
|
||||
// Document Template Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('document_template_id') AS num FROM document_templates"));
|
||||
$document_template_count = $row['num'];
|
||||
|
||||
// Shared Item Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('item_id') AS num FROM shared_items"));
|
||||
$shared_item_count = $row['num'];
|
||||
|
||||
// Company Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('company_id') AS num FROM companies"));
|
||||
$company_count = $row['num'];
|
||||
|
||||
// User Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('user_id') AS num FROM users"));
|
||||
$user_count = $row['num'];
|
||||
|
||||
// Category Expense Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('category_id') AS num FROM categories WHERE category_type = 'Expense'"));
|
||||
$category_expense_count = $row['num'];
|
||||
|
||||
// Category Income Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('category_id') AS num FROM categories WHERE category_type = 'Income'"));
|
||||
$category_income_count = $row['num'];
|
||||
|
||||
// Category Referral Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('category_id') AS num FROM categories WHERE category_type = 'Referral'"));
|
||||
$category_referral_count = $row['num'];
|
||||
|
||||
// Category Payment Method Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('category_id') AS num FROM categories WHERE category_type = 'Payment Method'"));
|
||||
$category_payment_method_count = $row['num'];
|
||||
|
||||
// Tag Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('tag_id') AS num FROM tags"));
|
||||
$tag_count = $row['num'];
|
||||
|
||||
// API Key Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('api_key_id') AS num FROM api_keys"));
|
||||
$api_key_count = $row['num'];
|
||||
|
||||
// Log Count
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('log_id') AS num FROM logs"));
|
||||
$log_count = $row['num'];
|
||||
|
||||
$postdata = http_build_query(
|
||||
array(
|
||||
'installation_id' => "$installation_id",
|
||||
'version' => "$current_version",
|
||||
'company_name' => "$company_name",
|
||||
'website' => "$website",
|
||||
'city' => "$city",
|
||||
'state' => "$state",
|
||||
'country' => "$country",
|
||||
'currency' => "$currency",
|
||||
'comments' => "$comments",
|
||||
'client_count' => $client_count,
|
||||
'ticket_count' => $ticket_count,
|
||||
'recurring_ticket_count' => $recurring_ticket_count,
|
||||
'calendar_event_count' => $calendar_event_count,
|
||||
'quote_count' => $quote_count,
|
||||
'invoice_count' => $invoice_count,
|
||||
'revenue_count' => $revenue_count,
|
||||
'recurring_invoice_count' => $recurring_invoice_count,
|
||||
'account_count' => $account_count,
|
||||
'tax_count' => $tax_count,
|
||||
'product_count' => $product_count,
|
||||
'payment_count' => $payment_count,
|
||||
'company_vendor_count' => $company_vendor_count,
|
||||
'expense_count' => $expense_count,
|
||||
'trip_count' => $trip_count,
|
||||
'transfer_count' => $transfer_count,
|
||||
'contact_count' => $contact_count,
|
||||
'location_count' => $location_count,
|
||||
'asset_count' => $asset_count,
|
||||
'software_count' => $software_count,
|
||||
'software_template_count' => $software_template_count,
|
||||
'credential_count' => $credential_count,
|
||||
'network_count' => $network_count,
|
||||
'certificate_count' => $certificate_count,
|
||||
'domain_count' => $domain_count,
|
||||
'service_count' => $service_count,
|
||||
'client_vendor_count' => $client_vendor_count,
|
||||
'vendor_template_count' => $vendor_template_count,
|
||||
'file_count' => $file_count,
|
||||
'document_count' => $document_count,
|
||||
'document_template_count' => $document_template_count,
|
||||
'shared_item_count' => $shared_item_count,
|
||||
'company_count' => $company_count,
|
||||
'user_count' => $user_count,
|
||||
'category_expense_count' => $category_expense_count,
|
||||
'category_income_count' => $category_income_count,
|
||||
'category_referral_count' => $category_referral_count,
|
||||
'category_payment_method_count' => $category_payment_method_count,
|
||||
'tag_count' => $tag_count,
|
||||
'api_key_count' => $api_key_count,
|
||||
'log_count' => $log_count,
|
||||
'config_theme' => "$config_theme",
|
||||
'config_enable_cron' => $config_enable_cron,
|
||||
'config_ticket_email_parse' => $config_ticket_email_parse,
|
||||
'config_module_enable_itdoc' => $config_module_enable_itdoc,
|
||||
'config_module_enable_ticketing' => $config_module_enable_ticketing,
|
||||
'config_module_enable_accounting' => $config_module_enable_accounting,
|
||||
'config_telemetry' => $config_telemetry,
|
||||
'collection_method' => 4
|
||||
)
|
||||
);
|
||||
|
||||
$opts = array('http' =>
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'header' => 'Content-type: application/x-www-form-urlencoded',
|
||||
'content' => $postdata
|
||||
)
|
||||
);
|
||||
|
||||
$context = stream_context_create($opts);
|
||||
|
||||
$result = file_get_contents('https://telemetry.itflow.org', false, $context);
|
||||
|
||||
}
|
||||
|
||||
logAudit("App", "Update", "$session_name ran updates");
|
||||
|
||||
flashAlert("Update successful");
|
||||
|
||||
sleep(1);
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['update_db'])) {
|
||||
|
||||
validateCSRFToken();
|
||||
|
||||
@@ -7,11 +7,12 @@ $repo_branch = getRepoBranch();
|
||||
$remote_ref = escapeshellarg("origin/$repo_branch");
|
||||
|
||||
/*
|
||||
* Everything git can tell us needs a shell. Where PHP cannot run one - shared hosting, a
|
||||
* hardened php.ini, an FPM pool locked down while the command line is not - the page cannot
|
||||
* say whether an update is waiting and the web server cannot apply one either, so the
|
||||
* application half of this page is replaced by the queue, which cron carries out. The
|
||||
* database half is plain PHP and works everywhere.
|
||||
* The web server never applies an application update - it queues one and cron runs it. The
|
||||
* shell gate below therefore only decides whether this page can READ the git remote to say
|
||||
* an update is waiting; where PHP cannot run one - shared hosting, a hardened php.ini, an
|
||||
* FPM pool locked down while the command line is not - the page offers the queue blind,
|
||||
* which is harmless when there is nothing to fetch. The database half is plain PHP and
|
||||
* works everywhere.
|
||||
*/
|
||||
$shell_available = shellCommandsAvailable();
|
||||
|
||||
@@ -109,10 +110,10 @@ $app_update_available = !empty($pending_commits);
|
||||
|
||||
<?php if (!$shell_available) { ?>
|
||||
<div class="alert alert-info">
|
||||
<h5><i class="fas fa-fw fa-info-circle me-2"></i>This server cannot run Git from the web</h5>
|
||||
PHP here has <code>exec</code> and <code>shell_exec</code> disabled, so this page can neither check for
|
||||
application updates nor apply one. Queue an update instead: cron runs it from the command line, which
|
||||
is usually not restricted the same way. Database updates are plain PHP and are unaffected.
|
||||
<h5><i class="fas fa-fw fa-info-circle me-2"></i>This server cannot check for updates</h5>
|
||||
PHP here has <code>exec</code> and <code>shell_exec</code> disabled, so this page cannot read the Git
|
||||
remote to tell you whether one is waiting. Queueing still works - cron runs the update from the command
|
||||
line, which is usually not restricted the same way. Database updates are plain PHP and are unaffected.
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
@@ -194,8 +195,8 @@ $app_update_available = !empty($pending_commits);
|
||||
|
||||
<?php if ($app_update_available && $db_update_available) { ?>
|
||||
<p class="text-muted">
|
||||
<i class="fas fa-fw fa-info-circle me-1"></i>Both are pending. Update the application files first -
|
||||
they bring the database migrations that the second step then applies.
|
||||
<i class="fas fa-fw fa-info-circle me-1"></i>Both are pending. Queueing the update covers both -
|
||||
cron applies the files and then the migrations they bring, in that order, in one run.
|
||||
</p>
|
||||
<?php } ?>
|
||||
|
||||
@@ -214,28 +215,14 @@ $app_update_available = !empty($pending_commits);
|
||||
</p>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($shell_available) { ?>
|
||||
<a class="btn btn-primary confirm-link" href="post.php?update&csrf_token=<?= $_SESSION['csrf_token'] ?>">
|
||||
<i class="fas fa-fw fa-download me-2"></i>Update App
|
||||
</a>
|
||||
<a class="btn btn-outline-danger ms-2 confirm-link" href="post.php?update&force_update=1&csrf_token=<?= $_SESSION['csrf_token'] ?>">
|
||||
<i class="fas fa-fw fa-hammer me-2"></i>Force Update
|
||||
</a>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($update_queue_available) { ?>
|
||||
<a class="btn btn-dark <?= $shell_available ? 'ms-2' : '' ?> confirm-link" href="post.php?queue_update&csrf_token=<?= $_SESSION['csrf_token'] ?>">
|
||||
<a class="btn btn-primary confirm-link" href="post.php?queue_update&csrf_token=<?= $_SESSION['csrf_token'] ?>">
|
||||
<i class="fas fa-fw fa-clock me-2"></i>Queue Update
|
||||
</a>
|
||||
<?php } ?>
|
||||
|
||||
<p class="text-muted mt-2 mb-0">
|
||||
<small>
|
||||
<?php if ($shell_available) { ?>
|
||||
Update App runs <code>git pull</code>. Force Update discards every local change and resets
|
||||
the files to <code><?= escapeHtml("origin/$repo_branch") ?></code> - use it only when a
|
||||
normal update will not apply. Both run inside this request and stop if PHP runs out of time.
|
||||
<?php } ?>
|
||||
<?php if ($update_queue_available) { ?>
|
||||
Queue Update hands the job to cron, which runs
|
||||
<code>scripts/update_cli.php</code> in its own process - it updates the files and then the
|
||||
|
||||
@@ -336,10 +336,11 @@ function getRepoBranch(): string
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether this PHP can run external commands at all. ITFlow updates itself with git, so the
|
||||
* update path needs exec() and shell_exec(); hosts that disable them - shared hosting, a
|
||||
* hardened php.ini, an FPM pool locked down while the CLI is not - can still update through
|
||||
* cron, which runs under a different php.ini and its own settings.
|
||||
* Whether this PHP can run external commands at all. Applying an update is cron's job now, so
|
||||
* the only thing the web tier still wants a shell for is READING git - checkForUpdates() and
|
||||
* the pending-commit list on Maintenance > Update. Hosts that disable exec()/shell_exec() -
|
||||
* shared hosting, a hardened php.ini, an FPM pool locked down while the CLI is not - lose the
|
||||
* "an update is waiting" readout, not the ability to update.
|
||||
*
|
||||
* function_exists() already reports a disabled function as missing. disable_functions is
|
||||
* read as well because some hardening extensions leave the function defined and refuse the
|
||||
|
||||
Reference in New Issue
Block a user