用于创建/操作固定宽度文本文件的 PHP 库 [英] PHP library for creating/manipulating fixed-width text files

查看:30
本文介绍了用于创建/操作固定宽度文本文件的 PHP 库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个 Web 应用程序,可以进行时间跟踪、工资单和人力资源管理.因此,我们必须编写大量固定宽度的数据文件以导出到其他系统(州税务申报、ACH 文件等).有没有人知道一个很好的库,您可以在其中定义记录类型/结构,然后在 OOP 范式中对它们进行操作?

We have a web application that does time-tracking, payroll, and HR. As a result, we have to write a lot of fixed-width data files for export into other systems (state tax filings, ACH files, etc). Does anyone know of a good library for this where you can define the record types/structures, and then act on them in an OOP paradigm?

这个想法将是一个类,您可以使用规范,然后使用所述规范的实例.IE:

The idea would be a class that you hand specifications, and then work with an instance of said specification. IE:

$icesa_file = new FixedWidthFile();
$icesa_file->setSpecification('icesa.xml');
$icesa_file->addEmployer( $some_data_structure );

其中 icesa.xml 是一个包含规范的文件,尽管您可以使用 OOP 调用自己定义它:

Where icesa.xml is a file that contains the spec, although you could just use OOP calls to define it yourself:

$specification = new FixedWidthFileSpecification('ICESA');
$specification->addRecordType(
    $record_type_name = 'Employer',
    $record_fields = array(
         array('Field Name', Width, Vailditation Type, options)
         )
     );

我不是在寻求关于如何编写这样一个库的建议——我只是想知道一个库是否已经存在.谢谢!!

I'm not looking for advice on how to write such a library--I just wanted to know if one already existed. Thank you!!

推荐答案

我不知道有什么库可以完全满足您的需求,但是推出您自己的类来处理这个问题应该相当简单.假设您主要对以这些格式写入数据感兴趣,我将使用以下方法:

I don't know of a library that does exactly what you want, but it should be rather straight-forward to roll your own classes that handle this. Assuming that you are mainly interested in writing data in these formats, I would use the following approach:

(1) 为固定宽度的字符串编写一个轻量级的格式化程序类.它必须支持用户定义的记录类型,并且在允许的格式方面应该是灵活的

(1) Write a lightweight formatter class for fixed width strings. It must support user defined record types and should be flexible with regard to allowed formats

(2) 为您使用的每种文件格式实例化此类并添加所需的记录类型

(2) Instantiate this class for every file format you use and add required record types

(3) 使用此格式化程序来格式化您的数据

(3) Use this formatter to format your data

正如您所建议的,您可以在 XML 中定义记录类型并在步骤 (2) 中加载此 XML 文件.我不知道您对 XML 的经验如何,但根据我的经验,XML 格式经常引起很多麻烦(可能是由于我自己对 XML 的无能).如果您打算只在 PHP 程序中使用这些类,那么在 XML 中定义格式并没有什么好处.如果您还需要在许多其他应用程序中使用文件格式定义,则使用 XML 是一个不错的选择.

As you suggested, you could define the record types in XML and load this XML file in step (2). I don't know how experienced you are with XML, but in my experience XML formats often causes a lot of headaches (probably due to my own incompetence regarding XML). If you are going to use these classes only in your PHP program, there's not much to gain from defining your format in XML. Using XML is a good option if you will need to use the file format definitions in many other applications as well.

为了说明我的想法,我认为您将如何使用这个建议的格式化程序类:

To illustrate my ideas, here is how I think you would use this suggested formatter class:

<?php
include 'FixedWidthFormatter.php' // contains the FixedWidthFormatter class
include 'icesa-format-declaration.php' // contains $icesaFormatter
$file = fopen("icesafile.txt", "w");

fputs ($file, $icesaFormatter->formatRecord( 'A-RECORD', array( 
    'year' => 2011, 
    'tein' => '12-3456789-P',
    'tname'=> 'Willie Nelson'
)));
// output: A2011123456789UTAX     Willie Nelson                                     

// etc...

fclose ($file);
?>

文件 icesa-format-declaration.php 可以像这样以某种方式包含格式声明:

The file icesa-format-declaration.php could contain the declaration of the format somehow like this:

<?php
$icesaFormatter = new FixedWidthFormatter();
$icesaFormatter->addRecordType( 'A-RECORD', array(
    // the first field is the record identifier
    // for A records, this is simply the character A
    'record-identifier' => array(
        'value' => 'A',  // constant string
        'length' => 1 // not strictly necessary
                      // used for error checking
    ),
    // the year is a 4 digit field
    // it can simply be formatted printf style
    // sourceField defines which key from the input array is used
    'year' =>  array(
        'format' => '% -4d',  // 4 characters, left justified, space padded
        'length' => 4,
        'sourceField' => 'year'
    ),
    // the EIN is a more complicated field
    // we must strip hyphens and suffixes, so we define
    // a closure that performs this formatting
    'transmitter-ein' => array(
        'formatter'=> function($EIN){
            $cleanedEIN =  preg_replace('/\D+/','',$EIN); // remove anything that's not a digit
            return sprintf('% -9d', $cleanedEIN); // left justified and padded with blanks
        },
        'length' => 9,
        'sourceField' => 'tein'
    ),
    'tax-entity-code' => array(
        'value' => 'UTAX',  // constant string
        'length' => 4
    ),
    'blanks' => array(
        'value' => '     ',  // constant string
        'length' => 5
    ),
    'transmitter-name' =>  array(
        'format' => '% -50s',  // 50 characters, left justified, space padded
        'length' => 50,
        'sourceField' => 'tname'
    ),
    // etc. etc.
));
?>

然后你只需要 FixedWidthFormatter 类本身,它看起来像这样:

Then you only need the FixedWidthFormatter class itself, which could look like this:

<?php

class FixedWidthFormatter {

    var $recordTypes = array();

    function addRecordType( $recordTypeName, $recordTypeDeclaration ){
        // perform some checking to make sure that $recordTypeDeclaration is valid
        $this->recordTypes[$recordTypeName] = $recordTypeDeclaration;
    }

    function formatRecord( $type, $data ) {
        if (!array_key_exists($type, $this->recordTypes)) {
            trigger_error("Undefinded record type: '$type'");
            return "";
        }
        $output = '';
        $typeDeclaration = $this->recordTypes[$type];
        foreach($typeDeclaration as $fieldName => $fieldDeclaration) {
            // there are three possible field variants:
            //  - constant fields
            //  - fields formatted with printf
            //  - fields formatted with a custom function/closure
            if (array_key_exists('value',$fieldDeclaration)) {
                $value = $fieldDeclaration['value'];
            } else if (array_key_exists('format',$fieldDeclaration)) {
                $value = sprintf($fieldDeclaration['format'], $data[$fieldDeclaration['sourceField']]);
            } else if (array_key_exists('formatter',$fieldDeclaration)) {
                $value = $fieldDeclaration['formatter']($data[$fieldDeclaration['sourceField']]);
            } else {
                trigger_error("Invalid field declaration for field '$fieldName' record type '$type'");
                return '';
            }

            // check if the formatted value has the right length
            if (strlen($value)!=$fieldDeclaration['length']) {
                trigger_error("The formatted value '$value' for field '$fieldName' record type '$type' is not of correct length ({$fieldDeclaration['length']}).");
                return '';
            }
            $output .= $value;
        }
        return $output . "\n";
    }
}


?>

如果您还需要读取支持,可以扩展 Formatter 类以允许读取,但这可能超出了本答案的范围.

If you need read support as well, the Formatter class could be extended to allow reading as well, but this might be beyond the scope of this answer.

这篇关于用于创建/操作固定宽度文本文件的 PHP 库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆