403Webshell
Server IP : 202.61.199.114  /  Your IP : 216.73.217.139
Web Server : nginx/1.22.1
System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64
User : web20 ( 1018)
PHP Version : 8.4.23
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/clients/client2/web32/web/tools/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/clients/client2/web32/web/tools/dedupe-cams.php
<?php
/**
 * Duplikat-Prüfer & -Löscher für live_cam Posts.
 *
 * Findet Cams, die DOPPELT angelegt wurden. Maßgeblich ist die _vx_cam_id:
 * dieselbe Cam-ID darf nur EINMAL existieren. Wird sie zweimal angelegt
 * (z.B. paralleler Cron + manueller Sync), hängt WordPress an den zweiten
 * Slug ein "-N" an -> name-cam-<camid>-2. Beides wird hier erkannt.
 *
 * Kanonisch (= bleibt erhalten) ist immer der ÄLTESTE Post (kleinste ID) je
 * Cam-ID -- exakt das, was der Syncer via lookup_by_cam_id() wiederfindet.
 * Alle weiteren Posts derselben Cam-ID sind Duplikate und werden gelöscht;
 * dazu werden verwaiste Attachments (Thumbnail, Galerie, Avatar) mit entfernt.
 *
 * Aufruf (CLI braucht PHP >=7.4 MIT mysqli -> hier: php8.4):
 *   CLI (anzeigen):   php8.4 tools/dedupe-cams.php
 *   CLI (löschen):    php8.4 tools/dedupe-cams.php --delete
 *   Browser (zeigen): /tools/dedupe-cams.php?token=1fa05e8f21a19788
 *   Browser (lösch.): /tools/dedupe-cams.php?token=1fa05e8f21a19788&delete=1
 *
 * Ohne --delete / &delete=1 wird NUR angezeigt (Dry-Run) -- nichts gelöscht.
 */

define( 'VXLC_DEDUPE_TOKEN', '1fa05e8f21a19788' );

$is_cli = ( PHP_SAPI === 'cli' );

// ---- Zugriffsschutz im Browser -------------------------------------------
if ( ! $is_cli ) {
    $token = isset( $_GET['token'] ) ? (string) $_GET['token'] : '';
    if ( ! hash_equals( VXLC_DEDUPE_TOKEN, $token ) ) {
        http_response_code( 403 );
        header( 'Content-Type: text/plain; charset=utf-8' );
        exit( "403 - falscher oder fehlender token\n" );
    }
    header( 'Content-Type: text/plain; charset=utf-8' );
}

// ---- WordPress laden ------------------------------------------------------
require __DIR__ . '/../wp-load.php';

if ( ! post_type_exists( 'live_cam' ) ) {
    fwrite( STDERR, "FEHLER: Post-Type 'live_cam' nicht registriert (Plugin aktiv?).\n" );
    exit( 1 );
}

$do_delete = $is_cli
    ? in_array( '--delete', $argv, true )
    : ( isset( $_GET['delete'] ) && $_GET['delete'] === '1' );

global $wpdb;

/**
 * Alle Cam-IDs sammeln, die mehr als einen Post besitzen.
 * Rückgabe: [ cam_id => [ post_id, post_id, ... ] ] aufsteigend nach post_id.
 */
$rows = $wpdb->get_results(
    "SELECT pm.meta_value AS cam_id, pm.post_id AS post_id, p.post_name, p.post_title, p.post_date
       FROM {$wpdb->postmeta} pm
       INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
      WHERE pm.meta_key = '_vx_cam_id'
        AND p.post_type = 'live_cam'
      ORDER BY CAST(pm.meta_value AS UNSIGNED) ASC, p.ID ASC",
    ARRAY_A
);

$by_cam = array();
foreach ( $rows as $r ) {
    $by_cam[ (string) $r['cam_id'] ][] = $r;
}

$groups = array_filter( $by_cam, function ( $posts ) {
    return count( $posts ) > 1;
} );

// ---- Ausgabe ---------------------------------------------------------------
$line = str_repeat( '=', 78 );
echo "$line\n";
echo "  live_cam Duplikat-Prüfer" . ( $do_delete ? '  [LÖSCHEN AKTIV]' : '  [DRY-RUN / nur anzeigen]' ) . "\n";
echo "$line\n";
echo "Gesamt live_cam Posts : " . count( $rows ) . "\n";
echo "Eindeutige Cam-IDs    : " . count( $by_cam ) . "\n";
echo "Cam-IDs mit Duplikaten: " . count( $groups ) . "\n";

if ( empty( $groups ) ) {
    echo "\n>> Keine Duplikate gefunden. Nichts zu tun.\n";
    exit( 0 );
}

$total_dupes  = 0;
$delete_ids   = array(); // post_id => cam_id

echo "\nGefundene Duplikate (kanonisch = ältester Post bleibt erhalten):\n\n";
foreach ( $groups as $cam_id => $posts ) {
    $keep = $posts[0]; // kleinste ID = ältester
    echo "Cam-ID $cam_id:\n";
    echo sprintf( "  BEHALTEN  #%-8d  %s  (%s)\n", $keep['post_id'], $keep['post_name'], $keep['post_date'] );
    for ( $i = 1; $i < count( $posts ); $i++ ) {
        $d = $posts[ $i ];
        $has_n = preg_match( '/-cam-\d+-\d+$/', $d['post_name'] ) ? ' [-N slug]' : '';
        echo sprintf( "  LÖSCHEN   #%-8d  %s  (%s)%s\n", $d['post_id'], $d['post_name'], $d['post_date'], $has_n );
        $delete_ids[ (int) $d['post_id'] ] = $cam_id;
        $total_dupes++;
    }
    echo "\n";
}

echo "Zu löschende Duplikat-Posts: $total_dupes\n";

if ( ! $do_delete ) {
    echo "\n(DRY-RUN) Es wurde NICHTS gelöscht.\n";
    echo "Zum Löschen erneut mit --delete (CLI) bzw. &delete=1 (Browser) aufrufen.\n";
    exit( 0 );
}

// ---- Löschen ---------------------------------------------------------------
echo "\n" . str_repeat( '-', 78 ) . "\nLösche...\n";

/**
 * Attachment nur löschen, wenn KEIN anderer Post es noch referenziert
 * (Thumbnail, Galerie, Avatar werden per Hash dedupliziert und ggf. geteilt).
 */
$attachment_in_use = function ( $att_id, $exclude_post_id ) use ( $wpdb ) {
    $att_id = (int) $att_id;
    if ( $att_id <= 0 ) return true;
    // Eltern-Beziehung
    $cnt = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_parent = %d AND ID <> %d AND post_type <> 'attachment'",
        $att_id, $exclude_post_id
    ) );
    if ( $cnt > 0 ) return true;
    // Referenz in Meta (_thumbnail_id, _vx_avatar_attachment, _vx_gallery_ids serialisiert)
    $like = '%' . $wpdb->esc_like( (string) $att_id ) . '%';
    $cnt = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM {$wpdb->postmeta}
          WHERE post_id <> %d
            AND ( ( meta_key = '_thumbnail_id' AND meta_value = %s )
               OR ( meta_key = '_vx_avatar_attachment' AND meta_value = %s )
               OR ( meta_key = '_vx_gallery_ids' AND meta_value LIKE %s ) )",
        $exclude_post_id, (string) $att_id, (string) $att_id, $like
    ) );
    return $cnt > 0;
};

$deleted_posts = 0;
$deleted_atts  = 0;

foreach ( $delete_ids as $post_id => $cam_id ) {
    // Attachments dieses Duplikats einsammeln
    $att_ids = array();
    $thumb = (int) get_post_thumbnail_id( $post_id );
    if ( $thumb ) $att_ids[] = $thumb;
    $avatar = (int) get_post_meta( $post_id, '_vx_avatar_attachment', true );
    if ( $avatar ) $att_ids[] = $avatar;
    $gallery = get_post_meta( $post_id, '_vx_gallery_ids', true );
    if ( is_array( $gallery ) ) {
        foreach ( $gallery as $g ) { if ( (int) $g ) $att_ids[] = (int) $g; }
    }
    // child-attachments per post_parent
    $children = get_posts( array(
        'post_type'   => 'attachment',
        'post_status' => 'inherit',
        'post_parent' => $post_id,
        'numberposts' => -1,
        'fields'      => 'ids',
    ) );
    foreach ( $children as $c ) $att_ids[] = (int) $c;
    $att_ids = array_unique( array_filter( $att_ids ) );

    foreach ( $att_ids as $att_id ) {
        if ( $attachment_in_use( $att_id, $post_id ) ) {
            echo "  ~ Attachment #$att_id noch in Benutzung -> behalten\n";
            continue;
        }
        if ( wp_delete_attachment( $att_id, true ) ) {
            $deleted_atts++;
        }
    }

    $res = wp_delete_post( $post_id, true ); // true = endgültig, kein Papierkorb
    if ( $res ) {
        $deleted_posts++;
        echo "  - Cam-ID $cam_id: Post #$post_id gelöscht\n";
    } else {
        echo "  ! Post #$post_id konnte NICHT gelöscht werden\n";
    }
}

echo "\n" . str_repeat( '=', 78 ) . "\n";
echo "FERTIG. Gelöscht: $deleted_posts Duplikat-Posts, $deleted_atts verwaiste Attachments.\n";
echo str_repeat( '=', 78 ) . "\n";

Youez - 2016 - github.com/yon3zu
LinuXploit