Chamilo is a learning management system focused on ease of use and accessibility
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
chamilo-lms/tests/scripts/delete_duplicate_links.php

155 lines
6.0 KiB

<?php
/* For licensing terms, see /license.txt */
/**
* This script removes duplicated links.
* It identifies duplicate links by URL,
* makes sure no usage is associated with the duplicated link, and
* that the duplicated link is not used in a learning path.
* A duplicated link will generally match the following criteria:
* - same URL field as the original
* - same title
* - same category_id
* - same on_homepage field
* - same target
* - same course, same session (otherwise considered a different link, a voluntary copy)
* - each have entries in c_item_property because it was created legitimately
* Possible duplicates can be found with a query like:
* SELECT iid, c_id, session_id, url, title, description, target, on_homepage FROM c_link WHERE c_id = 470 AND url like '%\__.%' ORDER BY url, title;
* This script should be located inside the tests/scripts/ folder to work.
* It can be run more than one time as it will only ever affect duplicate
* links.
* If you have a very large number of links, we recommend you temporarily
* comment out the api_item_property_update() calls in
* Link::deletelinkcategory() (which deletes a link *or* a category).
* Chances are there is not even a registry of those links there in the
* first place (they were probably duplicated through a short/broken process) and
* this is where most of the time is spent during deletion.
* @author Yannick Warnier <yannick.warnier@beeznest.com>
* @author Christian Fasanando <christian.fasanando@beeznest.com>
*/
exit; //remove this line to execute from the command line
use ChamiloSession as Session;
ini_set('memory_limit', '256M');
if (PHP_SAPI !== 'cli') {
die('This script can only be executed from the command line');
}
require_once __DIR__.'/../../main/inc/global.inc.php';
$debug = true;
$_user['user_id'] = 1;
Session::write('_user', $_user);
echo "[" . time() . "] Querying courses\n";
$sql = "SELECT id, code FROM course ORDER BY id";
$resCourse = Database::query($sql);
if ($resCourse === false) {
exit("Could not find any course\n");
}
$countCourses = Database::num_rows($resCourse);
echo "[" . time() . "] Found $countCourses courses\n";
$duplicatesCount = 0;
$originalsCount = 0;
$deletedCount = 0;
$itemsInLP = 0;
// Iterate through each course
while ($course = Database::fetch_assoc($resCourse)) {
if (empty($course['id'])) {
continue; // Skip invalid course IDs
}
if ($debug) {
echo "\n-= Course ".$course['id']." (".$course['code'].") =-\n----\n";
}
$sql2 = "SELECT iid, url, title, description, category_id, on_homepage, target, session_id
FROM c_link
WHERE c_id = " . $course['id'] . "
AND (session_id = 0 OR session_id IS NULL)
ORDER BY url, title, iid";
$res2 = Database::query($sql2);
if ($res2 === false) {
die("Error querying links in course code " . $course['code'] . "\n");
}
$links = [];
while ($item = Database::fetch_assoc($res2)) {
$links[] = $item;
}
// Track processed duplicates to avoid redundant operations
$processedDuplicates = [];
foreach ($links as $key => $original) {
$originalsCount++;
// Make sure we don't use a just-deleted link as original
if (in_array($original['iid'], $processedDuplicates)) {
continue;
}
foreach ($links as $key2 => $duplicate) {
if ($debug) {
echo "Checking potential duplicate link ".$duplicate['iid']." against original ".$original['iid']."\n";
}
if (
$key !== $key2 &&
!in_array($duplicate['iid'], $processedDuplicates) &&
$original['url'] === $duplicate['url'] &&
$original['title'] === $duplicate['title'] &&
$original['description'] === $duplicate['description'] &&
$original['category_id'] === $duplicate['category_id'] &&
$original['on_homepage'] === $duplicate['on_homepage'] &&
$original['target'] === $duplicate['target'] &&
$original['session_id'] === $duplicate['session_id'] &&
$original['iid'] < $duplicate['iid']
) {
$duplicatesCount++;
if ($debug) {
echo "\n[".date('Y-m-d h:i:s')."]\nDuplicate found in Course ID: " . $course['id'] . "\n";
echo "Original IID=" . $original['iid'] . ", Duplicate IID=" . $duplicate['iid'] . " ($duplicatesCount)\n";
}
// Check if duplicate exists in c_lp_item
$checkSql = "SELECT COUNT(*) as count FROM c_lp_item
WHERE ref = " . $duplicate['iid'] . "
AND c_id = " . $course['id'] . "
AND item_type = 'link'";
$checkResult = Database::query($checkSql);
$row = Database::fetch_assoc($checkResult);
if ($row['count'] > 0) {
$itemsInLP++;
if ($debug) {
echo "Duplicate in learning path: IID=" . $duplicate['iid'] . " (Original IID=" . $original['iid'] . ")\n";
}
continue; // Skip duplicates in learning paths
}
// Delete the duplicate
Link::deletelinkcategory($duplicate['iid'], 'link', $course['id'], true);
$deletedCount++;
$processedDuplicates[] = $duplicate['iid']; // Mark as processed
if ($debug) {
echo "Deleted Duplicate IID=" . $duplicate['iid'] . "\n";
}
}
}
}
if ($debug) {
echo "Ending course ".$course['id']."\n\n";
}
}
// Summary
if ($debug) {
echo "\nSummary:\n";
echo "- Total duplicates detected: $duplicatesCount\n";
echo "- Duplicates ignored (in learning paths): $itemsInLP\n";
echo "- Duplicates deleted: $deletedCount\n";
echo "[".time()."] Process complete.\n";
}