1: <?php
2: namespace NGS;
3:
4: require_once(__DIR__.'/Utils.php');
5:
6: use NGS\Utils;
7:
8: /**
9: * Used to represent bytestream objects
10: * Since strings in php are equivalent to bytestreams (1 character=1 byte),this
11: * functions as a simple wrapper around primitive php string with added sanity
12: * checks and helpers
13: *
14: * @property string $value Returns raw bytestream value as string
15: */
16: class ByteStream
17: {
18: protected $value;
19:
20: /**
21: * Creates a new instance from native string or stream resource
22: *
23: * @param string|\NGS\ByteStream|resource $value Primitive string, instance of ByteStream or a stream resource
24: * @throws InvalidArgumentException If argument is not a valid type
25: */
26: public function __construct($value='')
27: {
28: if (is_string($value)) {
29: $this->value = $value;
30: } elseif ($value instanceof \NGS\ByteStream) {
31: $this->value = $value->value;
32: } elseif (is_resource($value) && get_resource_type($value)==='stream') {
33: $this->value = stream_get_contents($value);
34: } else {
35: throw new \InvalidArgumentException('ByteStream could not be constructed from type "'.Utils::getType($value).'"');
36: }
37: }
38:
39: /**
40: * Factory method accepts base64 encoded string or other ByteStream instance
41: *
42: * @return \NGS\ByteStream
43: */
44: public static function fromBase64($value)
45: {
46: if ($value instanceof ByteStream) {
47: return new ByteStream($value);
48: } else {
49: if (!is_string($value)) {
50: throw new \InvalidArgumentException('Value was not a string, invalid type was "'.\NGS\Utils::getType($value).'"');
51: }
52: $raw = base64_decode($value);
53: // php has no easier way to check if string is valid base64
54: if (base64_encode($raw) !== $value) {
55: throw new \InvalidArgumentException('Value was not a valid base64 encoded string');
56: }
57: return new ByteStream($raw);
58: }
59: }
60:
61: /**
62: * Factory method accepts raw string or other ByteStream instance
63: *
64: * @return \NGS\ByteStream
65: */
66: public static function fromBinary($value)
67: {
68: if ($value instanceof ByteStream) {
69: return new ByteStream($value);
70: } else {
71: if (!is_string($value)) {
72: throw new \InvalidArgumentException('Value was not a string, invalid type was "'.\NGS\Utils::getType($value).'"');
73: }
74: return new ByteStream($value);
75: }
76: }
77:
78: /**
79: * Converts all elements in array to \NGS\Bytestream instances
80: * String elements must be base64 encoded
81: *
82: * @param array $items Source array, each element must be a valid argument for Bytestream constructor
83: * @param bool $allowNullValues
84: * @return array Resulting Bytestream array
85: * @throws \InvalidArgumentException If any element is null or invalid type
86: */
87: public static function toArray(array $items, $allowNullValues=false)
88: {
89: $results = array();
90: try {
91: foreach ($items as $key => $val) {
92: if ($allowNullValues && $val===null) {
93: $results[] = null;
94: } elseif ($val === null) {
95: throw new \InvalidArgumentException('Null value found in provided array');
96: } elseif (is_string($val)) {
97: $results[] = self::fromBase64($val);
98: } elseif (!$val instanceof \NGS\ByteStream) {
99: $results[] = new \NGS\ByteStream($val);
100: } else {
101: $results[] = $val;
102: }
103: }
104: }
105: catch(\Exception $e) {
106: throw new \InvalidArgumentException('Element at index '.$key.' could not be converted to ByteStream!', 42, $e);
107: }
108: return $results;
109: }
110:
111: /**
112: * Magic getter for value property
113: */
114: public function __get($name)
115: {
116: if($name==='value') {
117: return $this->value;
118: }
119: else {
120: throw new \InvalidArgumentException('ByteStream: Cannot get undefined property "'.$name.'"');
121: }
122: }
123:
124: /**
125: * Gets bytestream value encoded in base64
126: *
127: * @return string Base64 encoded bytestream
128: */
129: public function __toString()
130: {
131: return $this->toBase64();
132: }
133:
134: /**
135: * Gets bytestream value encoded in base64
136: *
137: * @return string Base64 encoded bytestream
138: */
139: public function toBase64()
140: {
141: return \base64_encode($this->value);
142: }
143:
144: /**
145: * Checks for equality against another ByteStream instance
146: *
147: * @param Bytestream $other Instance to compare with
148: * @return bool
149: */
150: public function equals(\NGS\ByteStream $other)
151: {
152: return $this->value === $other->value;
153: }
154:
155: /**
156: * Gets bytestream size (number of bytes)
157: *
158: * @return int Bytestream size
159: */
160: public function size()
161: {
162: return strlen($this->value);
163: }
164:
165: /**
166: * Gets raw value
167: *
168: * @return string Bytestream value
169: */
170: public function getValue()
171: {
172: return $this->value;
173: }
174: }
175: