Complex classes like RequestSigner often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use RequestSigner, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
8 | class RequestSigner |
||
9 | { |
||
10 | const SHA256 = 'x509+sha256'; |
||
11 | const SHA1 = 'x509+sha1'; |
||
12 | const NONE = 'none'; |
||
13 | |||
14 | /** |
||
15 | * @var string |
||
16 | */ |
||
17 | private $type; |
||
18 | |||
19 | /** |
||
20 | * @var int |
||
21 | */ |
||
22 | private $algoConst; |
||
23 | |||
24 | /** |
||
25 | * @var X509CertificatesBuf |
||
26 | */ |
||
27 | private $certificates; |
||
28 | |||
29 | /** |
||
30 | * @var resource |
||
31 | */ |
||
32 | private $privateKey; |
||
33 | |||
34 | /** |
||
35 | * @param string $type |
||
36 | * @param string $keyFile |
||
37 | * @param string $certFile |
||
38 | * @throws \Exception |
||
39 | */ |
||
40 | public function __construct($type = null, $keyFile = '', $certFile = '') |
||
57 | |||
58 | /** |
||
59 | * @return RequestSigner |
||
60 | */ |
||
61 | public static function none() |
||
65 | |||
66 | /** |
||
67 | * @param string $keyFile |
||
68 | * @param string $certFile |
||
69 | * @return RequestSigner |
||
70 | */ |
||
71 | public static function sha1($keyFile, $certFile) |
||
75 | |||
76 | /** |
||
77 | * @param string $keyFile |
||
78 | * @param string $certFile |
||
79 | * @return RequestSigner |
||
80 | */ |
||
81 | public static function sha256($keyFile, $certFile) |
||
85 | |||
86 | /** |
||
87 | * @return bool |
||
88 | */ |
||
89 | public function supportsSha256() |
||
93 | |||
94 | /** |
||
95 | * @param string $keyFile - path to key file |
||
96 | * @param string $certFile - path to certificate chain file |
||
97 | * @throws \Exception |
||
98 | */ |
||
99 | private function initialize($keyFile, $certFile) |
||
132 | |||
133 | /** |
||
134 | * @param string $data |
||
135 | * @return string |
||
136 | * @throws \Exception |
||
137 | */ |
||
138 | private function signData($data) |
||
151 | |||
152 | /** |
||
153 | * Applies the configured signature algorithm, adding values to |
||
154 | * the protobuf: 'pkiType', 'signature', 'pkiData' |
||
155 | * |
||
156 | * @param PaymentRequestBuf $request |
||
157 | * @return PaymentRequestBuf |
||
158 | * @throws \Exception |
||
159 | */ |
||
160 | public function sign(PaymentRequestBuf $request) |
||
174 | |||
175 | /** |
||
176 | * @param PaymentRequestBuf $request |
||
177 | * @return bool |
||
178 | */ |
||
179 | public function verify(PaymentRequestBuf $request) |
||
180 | { |
||
181 | $type = $request->getPkiType(); |
||
182 | if ($type === self::NONE) { |
||
183 | return true; |
||
184 | } |
||
185 | |||
186 | if ($type === self::SHA256) { |
||
187 | $algorithm = OPENSSL_ALGO_SHA256; |
||
188 | } else if ($type === self::SHA1) { |
||
189 | $algorithm = OPENSSL_ALGO_SHA1; |
||
190 | } else { |
||
191 | throw new \RuntimeException('Unsupported signature algorithm'); |
||
192 | } |
||
193 | |||
194 | $clone = clone $request; |
||
195 | $clone->setSignature(''); |
||
196 | $data = $clone->serialize(); |
||
197 | |||
198 | // Parse the public key |
||
199 | $certificates = new X509CertificatesBuf(); |
||
200 | $certificates->parse($clone->getPkiData()); |
||
201 | $certificate = $this->der2pem($certificates->getCertificate(0)); |
||
202 | $pubkeyid = openssl_pkey_get_public($certificate); |
||
203 | |||
204 | return 1 === openssl_verify($data, $request->getSignature(), $pubkeyid, $algorithm); |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Checks whether the decoded certificate is a root / self-signed certificate |
||
209 | * @param array $certificate |
||
210 | * @return bool |
||
211 | */ |
||
212 | private function isRoot($certificate) |
||
216 | |||
217 | /** |
||
218 | * Fetches parent certificates using network requests |
||
219 | * Todo: review use of file_get_contents |
||
220 | * @param $leafCertificate |
||
221 | * @return false|string |
||
222 | */ |
||
223 | private function fetchCertificateParent($leafCertificate) |
||
241 | |||
242 | /** |
||
243 | * Parses a PEM or DER certificate |
||
244 | * @param string $certData |
||
245 | * @return array |
||
246 | */ |
||
247 | private function parseCertificate($certData) |
||
260 | |||
261 | /** |
||
262 | * @param $certData |
||
263 | * @return array |
||
264 | */ |
||
265 | private function der2pem($certData) |
||
275 | |||
276 | /** |
||
277 | * Decode PEM data, return the internal DER data |
||
278 | * @param string $pem_data - pem certificate data |
||
279 | * @return string |
||
280 | */ |
||
281 | private function pem2der($pem_data) |
||
293 | |||
294 | /** |
||
295 | * @param string $leaf - path to a file with certificates |
||
296 | * @return array|bool |
||
297 | */ |
||
298 | private function fetchChain($leaf) |
||
321 | } |
||
322 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.