Skip to content

Commit 5482183

Browse files
committed
Initial commit
0 parents  commit 5482183

File tree

129 files changed

+5736
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+5736
-0
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
results.csv
2+
results.md
3+
vendor
4+
composer.lock
5+
*.db
6+
config.php
7+
*.sqlite
8+
.php-cs-fixer.cache

.php-cs-fixer.dist.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
/*
3+
* This document has been generated with
4+
* https://mlocati.github.io/php-cs-fixer-configurator/#version:3.0.0-rc.1|configurator
5+
* you can change this configuration by importing this file.
6+
*
7+
*/
8+
9+
$config = include 'vendor/phpfui/phpunit-syntax-coverage/PhpCsFixer.php';
10+
11+
return $config->setFinder(PhpCsFixer\Finder::create()
12+
->exclude('vendor')
13+
->in(__DIR__.'/SOB')
14+
);

SOB/BaseLine.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace SOB;
4+
5+
class BaseLine
6+
{
7+
private int $memory = 0;
8+
9+
private \SebastianBergmann\Timer\Timer $timer;
10+
11+
public function __construct()
12+
{
13+
$this->memory = \memory_get_usage();
14+
$this->timer = new \SebastianBergmann\Timer\Timer();
15+
$this->timer->start();
16+
}
17+
18+
public function getMemory() : int
19+
{
20+
return \memory_get_usage() - $this->memory;
21+
}
22+
23+
public function stop() : float
24+
{
25+
return $this->timer->stop()->asSeconds();
26+
}
27+
}

SOB/CSV/FileReader.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace SOB\CSV;
4+
5+
/**
6+
* A simple CSV reader based on a file containing CSV data
7+
*
8+
* @inheritDoc
9+
*/
10+
class FileReader extends Reader
11+
{
12+
public function __construct(private readonly string $fileName, bool $headerRow = true, string $separator = ',', string $enclosure = '"', string $escape = '\\')
13+
{
14+
parent::__construct(null, $headerRow, $separator, $enclosure, $escape);
15+
}
16+
17+
protected function open() : static
18+
{
19+
if (\file_exists($this->fileName))
20+
{
21+
if ($this->stream)
22+
{
23+
\fclose($this->stream);
24+
$this->stream = null;
25+
}
26+
$this->stream = @\fopen($this->fileName, 'r');
27+
}
28+
29+
return $this;
30+
}
31+
}

SOB/CSV/FileWriter.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace SOB\CSV;
4+
5+
/**
6+
* \PHPFUI\Tools\CSVWriter: a simple class to output a CSV file given data in an array
7+
*
8+
* Features:
9+
* - User specified delimiter (default: comma)
10+
* - Auto header row generation
11+
* - Sparse array output where emtpy columns are empty in the output
12+
*/
13+
class FileWriter extends Writer
14+
{
15+
/**
16+
* @var resource $out opened output file stream
17+
*/
18+
private $out;
19+
20+
/**
21+
* Make a \CSV\File\Writer.
22+
*
23+
* @param string $filename to be output. If $download is true then this is the name the user will see. Avoid OS specific filespec conventions. If $download is false, then you can specify a directory or other OS specific filespec.
24+
*/
25+
public function __construct(string $filename, private readonly bool $download = true, string $separator = ',', string $enclosure = '"', string $escape = '\\', string $eol = "\n")
26+
27+
{
28+
if ($this->download)
29+
{
30+
\header('Content-Type: application/csv');
31+
\header('Content-Disposition: inline; filename="' . $filename . '"');
32+
\header('Cache-Control: private, max-age=0, must-revalidate');
33+
\header('Pragma: public');
34+
$this->out = \fopen('php://output', 'w');
35+
}
36+
else
37+
{
38+
$this->out = \fopen($filename, 'w');
39+
}
40+
parent::__construct($this->out, $separator, $enclosure, $escape, $eol);
41+
}
42+
43+
public function __destruct()
44+
{
45+
\fclose($this->out);
46+
47+
if ($this->download)
48+
{
49+
exit;
50+
}
51+
}
52+
}

SOB/CSV/Reader.php

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<?php
2+
3+
namespace SOB\CSV;
4+
5+
/**
6+
* Base class for a simple CSV reader supporting files, string or streams as input
7+
*
8+
* Emulates an array of records (arrays), implimented as an Iterator, so can be used in a foreach statements.
9+
*
10+
* - If your CSV has headers (the default), then the keys of the returned array will be the header values.
11+
* - You can also specify a different field separator, for example ("\t") for tabs.
12+
* - Use rewind to reset to the top of the file.
13+
* - The header record is NEVER returned as a record. The first iteration will be the first record in the file, excluding the header record if specified.
14+
* - An empty stream will return -1 as the current index.
15+
*
16+
* @implements \Iterator<array<string, string>>
17+
*/
18+
abstract class Reader implements \Iterator
19+
{
20+
/** @var array<string, string> */
21+
private array $current = [];
22+
23+
/** @var array<string> */
24+
private array $headers = [];
25+
26+
private int $index = 0;
27+
28+
/**
29+
* @param ?resource $stream
30+
*/
31+
public function __construct(protected $stream, private readonly bool $headerRow, private readonly string $separator, private string $enclosure, private string $escape)
32+
{
33+
$this->rewind();
34+
}
35+
36+
/** @return array<string, string> */
37+
public function current() : array
38+
{
39+
return $this->current;
40+
}
41+
42+
/**
43+
* @return int index of the record in the CSV stream. Zero is index of first data record. -1 means the CSV stream is empty
44+
*/
45+
public function key() : int
46+
{
47+
return $this->index;
48+
}
49+
50+
/**
51+
* Load the next record in the stream
52+
*/
53+
public function next() : void
54+
{
55+
$this->current = [];
56+
57+
if ($this->stream)
58+
{
59+
$array = \fgetcsv($this->stream, 0, $this->separator, $this->enclosure, $this->escape);
60+
61+
if ($array)
62+
{
63+
++$this->index;
64+
65+
if ($this->headers)
66+
{
67+
foreach ($this->headers as $index => $header)
68+
{
69+
if (isset($array[$index]))
70+
{
71+
$this->current[$header] = $array[$index];
72+
}
73+
else
74+
{
75+
break;
76+
}
77+
}
78+
}
79+
else
80+
{
81+
$this->current = $array;
82+
}
83+
}
84+
}
85+
}
86+
87+
/**
88+
* rewind the reader to the first record
89+
*/
90+
public function rewind() : void
91+
{
92+
$this->index = -1;
93+
$this->open();
94+
95+
if ($this->stream)
96+
{
97+
\rewind($this->stream);
98+
99+
if ($this->headerRow)
100+
{
101+
$this->headers = \fgetcsv($this->stream, 0, $this->separator, $this->enclosure, $this->escape);
102+
}
103+
}
104+
$this->next();
105+
}
106+
107+
/**
108+
* You can specify headers if your file does not include them. The headers will be used as the key in the returned associative array for each record.
109+
*
110+
* @param array<string> $headers of strings
111+
*/
112+
public function setHeaders(array $headers) : static
113+
{
114+
$this->headers = $headers;
115+
116+
return $this;
117+
}
118+
119+
public function valid() : bool
120+
{
121+
return $this->current && $this->stream;
122+
}
123+
124+
/**
125+
* Override the open method to support your data type
126+
*/
127+
protected function open() : static
128+
{
129+
return $this;
130+
}
131+
}

SOB/CSV/StreamReader.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace SOB\CSV;
4+
5+
/**
6+
* A simple CSV reader based on an already open stream
7+
*
8+
* @inheritDoc
9+
*/
10+
class StreamReader extends Reader
11+
{
12+
/**
13+
* @param ?resource $stream
14+
*/
15+
public function __construct(protected $stream, bool $headerRow = true, string $separator = ',', string $enclosure = '"', string $escape = '\\')
16+
{
17+
parent::__construct($stream, $headerRow, $separator, $enclosure, $escape);
18+
$this->rewind();
19+
}
20+
}

SOB/CSV/StreamWriter.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace SOB\CSV;
4+
5+
/**
6+
* Since the \CSV\Writer works perfectly for streams, just make a new type since we can't make instantiate an abstract class
7+
*
8+
* User is responsible for opening and closing the stream.
9+
*/
10+
class StreamWriter extends Writer
11+
{
12+
}

SOB/CSV/StringReader.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace SOB\CSV;
4+
5+
/**
6+
* A simple CSV reader based on CSV data in a string
7+
*
8+
* @inheritDoc
9+
*/
10+
class StringReader extends Reader
11+
{
12+
public function __construct(private readonly string $data, bool $headerRow = true, string $separator = ',', string $enclosure = '"', string $escape = '\\')
13+
{
14+
parent::__construct(null, $headerRow, $separator, $enclosure, $escape);
15+
}
16+
17+
protected function open() : static
18+
{
19+
if ($this->stream)
20+
{
21+
\fclose($this->stream);
22+
}
23+
$this->stream = \fopen('php://memory', 'r+');
24+
\fwrite($this->stream, $this->data);
25+
26+
return $this;
27+
}
28+
}

SOB/CSV/StringWriter.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace SOB\CSV;
4+
5+
/**
6+
* \CSV\StringWriter
7+
*
8+
* uses __toString for output of CSV data
9+
*/
10+
class StringWriter extends Writer implements \Stringable
11+
{
12+
/**
13+
* @var resource $out stream for output
14+
*/
15+
private $out;
16+
17+
/**
18+
* Create a \CSV\StringWriter
19+
*/
20+
public function __construct(string $separator = ',', string $enclosure = '"', string $escape = '\\', string $eol = "\n")
21+
{
22+
$this->out = \fopen('php://memory', 'w');
23+
parent::__construct($this->out, $separator, $enclosure, $escape, $eol);
24+
}
25+
26+
public function __toString() : string
27+
{
28+
\rewind($this->out);
29+
30+
return \stream_get_contents($this->out);
31+
}
32+
}

0 commit comments

Comments
 (0)